贴工程目录,其中bll目录下是service+dao层,common是一些公用的模块及功能类,web是controller层
用到了druid及Redis,工具及配置类目录(本文不介绍如何配置druid及Redis,但是我会把源文件放上)
web文件目录结构
接下来,说下大体的学习研究思路,在这块我是分了三部分来做验证的,这三部分只有securityconfig配置类有所区别
第一部分就是前后端不分离的security认证;
第二部是前后端分离,使用security+JWT认证;
第三部分是一个项目中既包含前段的web验证,也包含API的jwt认证;
一、第一部分的验证:
pom文件
1 <!-- security --> 2 <dependency> 3 <groupId>org.springframework.boot</groupId> 4 <artifactId>spring-boot-starter-security</artifactId> 5 </dependency> 6 <!-- jwt --> 7 <dependency> 8 <groupId>io.jsonwebtoken</groupId> 9 <artifactId>jjwt</artifactId> 10 <version>0.9.0</version> 11 </dependency>
配置类中会用到的常量参数
# JWT
jwt.secret=secret
## 过期时间 毫秒
jwt.expiration=7200000
## 请求头
jwt.token_header=Authorization
## token 前缀
jwt.token_prefix=Bearer
spring security configuration配置类
package com.ek.security.config; import com.ek.security.EkUserDetailsService; import com.ek.security.handler.EkAuthenticationEntryPoint; import com.ek.security.handler.EkAuthenticationFailureHandler; import com.ek.security.handler.EkAuthenticationSuccessHandler; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.util.matcher.RequestMatcher; import javax.servlet.http.HttpServletRequest; /** * @ClassName: EkWebSecurityConfig * @Description: 前后端不分离的security安全认证 * @Author: edi_kai * @Version: V2.0 **/ @Configuration public class EkWebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private EkUserDetailsService userDetailsService; @Autowired private EkAuthenticationEntryPoint authenticationEntryPoint; @Autowired private EkAuthenticationFailureHandler authenticationFailureHandler; @Autowired private EkAuthenticationSuccessHandler authenticationSuccessHandler; @Autowired PasswordEncoder passwordEncoder; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 添加自定义认证 auth .userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder) ; } @Override protected void configure(HttpSecurity http) throws Exception { // http.authorizeRequests().antMatchers("/**").permitAll(); http.csrf().disable() //此处必须设置csrf disable,原因还不知道,对CSRF不太了解,后续我会查一下资料,然后在补充说明 // .and() .httpBasic().authenticationEntryPoint(authenticationEntryPoint) // 没有凭证的操作,该部分不需要,可以不添加 .and() .authorizeRequests() .antMatchers("/", "/index", "/toLogin", "/fail", "/druid/**").permitAll() //需要忽略的请求链接 .anyRequest().authenticated() // .access("@rbacauthorityservice.hasPermission(request,authentication)") // RBAC 动态 url 认证 .and() .formLogin().loginPage("/index") //指定自己的登录页面 .loginProcessingUrl("/toLogin") // 登录action .usernameParameter("logName") // 登录用户名 .passwordParameter("password") //密码 .defaultSuccessUrl("/success", false) //设置登陆成功后跳转的页面 .failureHandler(authenticationFailureHandler) //登录失败拦截器,也可以配置到指定的失败页面,我没写 // .successHandler(authenticationSuccessHandler) .and() .logout() ; } }
接下来看下该配置类中用到的其他配置类
EkUserDetails用户认证实体类,自己添加get/set方法,基本的Java类,不需要添加任何注解
private String loginName; private String password; private String userName; private String userId; private Set<? extends GrantedAuthority> authorities; // 权限
EkUserDetailsService登录认证,我这边没有配置权限,只是为了验证spring-security
package com.ek.security; import com.ek.bean.base.EkUser; import com.ek.service.base.IEkUserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; /** * @ClassName: EkUserDetailsService * @Description: TODO * @Author: edi_kai * @Date: 2019-08-06 * @Version: V2.0 **/ @Component public class EkUserDetailsService implements UserDetailsService { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private IEkUserService userService; @Override public UserDetails loadUserByUsername(String loginName) throws UsernameNotFoundException { EkUserDetails userDetails = null; EkUser dbUser = userService.selectByLogName(loginName); if (null != dbUser){ userDetails = new EkUserDetails(); userDetails.setLoginName(dbUser.getLogName()); userDetails.setPassword(dbUser.getPassWord()); userDetails.setUserName(dbUser.getUserName()); }else { log.error("{} is not exist.", loginName); throw new UsernameNotFoundException(String.format("%s is not exist.", loginName)); } return userDetails; } }
EkAuthenticationEntryPoint 未登录的配置类
package com.ek.security.handler; import com.alibaba.fastjson.JSON; import com.ek.msg.JsonMsg; import org.springframework.security.core.AuthenticationException; import org.springframework.security.web.AuthenticationEntryPoint; import org.springframework.stereotype.Component; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @ClassName: EkAuthenticationEntryPoint * @Description: TODO * @Author: edi_kai * @Date: 2019-08-06 * @Version: V2.0 **/ @Component public class EkAuthenticationEntryPoint implements AuthenticationEntryPoint { @Override public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { httpServletResponse.setHeader("Access-Control-Allow-Origin", "*"); httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); httpServletResponse.setHeader("Access-Control-Allow-Credentials","true"); // 设定类容为json的格式 httpServletResponse.setContentType("application/json;charset=UTF-8"); JsonMsg jsonMsg = new JsonMsg(); jsonMsg.setCode(402); jsonMsg.setMsg("未登录"); httpServletResponse.getWriter().write(JSON.toJSONString(jsonMsg)); httpServletResponse.sendError(402,"未登录"); } }
EkAuthenticationFailureHandler 认证失败配置类
@Component public class EkAuthenticationFailureHandler implements AuthenticationFailureHandler { @Override public void onAuthenticationFailure(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e) throws IOException, ServletException { httpServletResponse.setHeader("Access-Control-Allow-Origin", "*"); httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); httpServletResponse.setHeader("Access-Control-Allow-Credentials","true"); // 设定类容为json的格式 httpServletResponse.setContentType("application/json;charset=UTF-8"); JsonMsg jsonMsg = new JsonMsg(); jsonMsg.setCode(400); jsonMsg.setMsg("登录失败"); httpServletResponse.getWriter().write(JSON.toJSONString(jsonMsg)); } }
EkAuthenticationSuccessHandler 认证成功配置类
@Component public class EkAuthenticationSuccessHandler implements AuthenticationSuccessHandler { @Override public void onAuthenticationSuccess(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Authentication authentication) throws IOException, ServletException { httpServletResponse.setHeader("Access-Control-Allow-Origin", "*"); httpServletResponse.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE"); httpServletResponse.setHeader("Access-Control-Allow-Credentials","true"); // 设定类容为json的格式 httpServletResponse.setContentType("application/json;charset=UTF-8"); JsonMsg jsonMsg = new JsonMsg(); jsonMsg.setCode(200); jsonMsg.setMsg("登录成功"); httpServletResponse.getWriter().write(JSON.toJSONString(jsonMsg)); } }
EkPasswordEncoder 密码加密配置类
@Component public class EkPasswordEncoder implements PasswordEncoder { PasswordEncoder passwordEncoder = new BCryptPasswordEncoder(14); @Override public String encode(CharSequence charSequence) { System.out.println(charSequence); System.out.println(passwordEncoder.encode(charSequence)); return passwordEncoder.encode(charSequence); } @Override public boolean matches(CharSequence charSequence, String s) { System.out.println(String.format("charSequence=%s, s=%s", charSequence, s)); System.out.println(String.format("passwordEncoder.matches=%s", passwordEncoder.matches(charSequence, s))); return passwordEncoder.matches(charSequence, s); } }
到这里配置就算完成了,启动服务就可以看到效果了,没有登录的情况下访问permitAll()链接都会跳转到/index登录页,登录成功后再跳转。
二、JWT认证
我们只需要修改securityconfig配置类,并添加JWT配置即可其他不用修改
修改后的security配置类,我重新定义了个类,把注释去掉即可
package com.ek.security.config; import com.ek.security.EkUserDetailsService; import com.ek.security.handler.EkAuthenticationEntryPoint; import com.ek.security.handler.EkAuthenticationFailureHandler; import com.ek.security.handler.EkAuthenticationSuccessHandler; import com.ek.security.jwt.EkJwtAuthorizationTokenFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.config.BeanIds; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; /** * @ClassName: EkWebSecurityConfig * @Description: 前后端分离,后端security安全认证 * @Author: edi_kai * @Date: 2019-08-06 * @Version: V2.0 **/ //@Configuration //@EnableWebSecurity //@EnableGlobalMethodSecurity(prePostEnabled = true) public class EkApiSecurityConfig extends WebSecurityConfigurerAdapter { // @Autowired // private EkUserDetailsService userDetailsService; // @Autowired // private EkAuthenticationEntryPoint authenticationEntryPoint; // @Autowired // private EkAuthenticationFailureHandler authenticationFailureHandler; // @Autowired // private EkAuthenticationSuccessHandler authenticationSuccessHandler; // @Autowired // PasswordEncoder passwordEncoder; // @Autowired // EkJwtAuthorizationTokenFilter jwtAuthorizationTokenFilter; // // @Override // protected void configure(AuthenticationManagerBuilder auth) throws Exception { // // 添加自定义认证 // auth // .userDetailsService(userDetailsService) // .passwordEncoder(passwordEncoder) // ; // } // @Override // protected void configure(HttpSecurity http) throws Exception { //// http.authorizeRequests().antMatchers("/**").permitAll(); // http.cors().and().csrf().disable() //// .and() // .httpBasic().authenticationEntryPoint(authenticationEntryPoint) // .and() // .authorizeRequests() // .antMatchers("/", "/index", "/toLogin", "/fail", "/druid/**").permitAll() // .anyRequest().authenticated() // // .access("@rbacauthorityservice.hasPermission(request,authentication)") // RBAC 动态 url 认证 // .and() // .formLogin()//指定自己的登录页面 // .failureHandler(authenticationFailureHandler) // .successHandler(authenticationSuccessHandler) // .and() // .logout() // .and() // .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // .and() // .addFilterBefore(jwtAuthorizationTokenFilter, UsernamePasswordAuthenticationFilter.class) // ; // } // // @Bean(name = BeanIds.AUTHENTICATION_MANAGER) // @Override // public AuthenticationManager authenticationManagerBean() throws Exception { // return super.authenticationManagerBean(); // } }
JWT配置类
package com.ek.security.jwt; import com.ek.security.EkUserDetails; import com.ek.util.redis.EkRedisUtil; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Clock; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.impl.DefaultClock; import org.apache.commons.lang3.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Component; import java.io.Serializable; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.function.Function; /** * @ClassName: EkJwtTokenUtil * @Description: JWT工具类,配合Redis * @Author: qin_hqing * @Date: 2019-08-07 * @Version: V2.0 **/ @Component public class EkJwtTokenUtil implements Serializable { private Logger log = LoggerFactory.getLogger(this.getClass()); private static final long serialVersionUID = -3301605591108950415L; // 权限缓存前缀 private static final String REDIS_PREFIX_AUTH = "auth:"; // 用户信息缓存前缀 private static final String REDIS_PREFIX_USER = "user-details:"; @Autowired private EkRedisUtil redisUtil; @Value("${jwt.secret}") private String secret; @Value("${jwt.expiration}") private Long expiration; @Value("${jwt.token_header}") private String tokenHeader; private Clock clock = DefaultClock.INSTANCE; /** * 生成token * @param userDetails * @return */ public String generateToken(UserDetails userDetails) { EkUserDetails ekUserDetails = (EkUserDetails) userDetails; Map<String, Object> claims = new HashMap<>(); String token = doGenerateToken(claims, ekUserDetails.getLoginName()); String key = String.format("%s%s", REDIS_PREFIX_AUTH, ekUserDetails.getLoginName()); redisUtil.set(key, token, expiration); return token; } private String doGenerateToken(Map<String, Object> claims, String subject) { final Date createdDate = clock.now(); final Date expirationDate = calculateExpirationDate(createdDate); return Jwts.builder() .setClaims(claims) .setSubject(subject) .setIssuedAt(createdDate) .setExpiration(expirationDate) .signWith(SignatureAlgorithm.HS512, secret) .compact(); } private Date calculateExpirationDate(Date createdDate) { return new Date(createdDate.getTime() + expiration); } /** * 校验token是否合法 * @param token * @return */ public Boolean validateToken(String token) { final String logName = getUsernameFromToken(token); return StringUtils.isNotEmpty(token) && !isTokenExpired(token); } /** * 校验token是否合法 * @param token * @param userDetails * @return */ public Boolean validateToken(String token, UserDetails userDetails) { EkUserDetails user = (EkUserDetails) userDetails; final String logName = getUsernameFromToken(token); String key = String.format("%s%s", REDIS_PREFIX_AUTH, user.getLoginName()); if (redisUtil.containsKey(key)){ return StringUtils.isNotEmpty(token) && token.equals(redisUtil.get(key)) && (logName.equals(user.getLoginName()) && !isTokenExpired(token)); } return false; } /** * 根据token获取登录用户名 * @param token * @return */ public String getUsernameFromToken(String token) { return getClaimFromToken(token, Claims::getSubject); } public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) { final Claims claims = getAllClaimsFromToken(token); return claimsResolver.apply(claims); } private Claims getAllClaimsFromToken(String token) { return Jwts.parser() .setSigningKey(secret) .parseClaimsJws(token) .getBody(); } private Boolean isTokenExpired(String token) { final Date expiration = getExpirationDateFromToken(token); return expiration.before(clock.now()); } public Date getExpirationDateFromToken(String token) { return getClaimFromToken(token, Claims::getExpiration); } /** * 添加EkUserDetails缓存 * @param userDetails */ public void putUserDetails(UserDetails userDetails){ EkUserDetails user = (EkUserDetails) userDetails; String key = String.format("%s%s", REDIS_PREFIX_USER, user.getLoginName()); redisUtil.set(key, user, expiration); } /** * 根据token获取EkUserDetails * @param token * @return */ public UserDetails getUserDetails(String token){ String logName = getUsernameFromToken(token); String key = String.format("%s%s", REDIS_PREFIX_USER, logName); if (redisUtil.containsKey(key)){ return redisUtil.get(key, EkUserDetails.class); } return null; } }
package com.ek.security.jwt; import com.ek.bean.base.EkUser; import com.ek.security.EkUserDetails; import com.ek.service.base.IEkUserService; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import java.io.IOException; /** * @ClassName: EkJwtAuthorizationTokenFilter * @Description: JWT拦截器,对token进行验证 * @Author: qin_hqing * @Date: 2019-08-07 * @Version: V2.0 **/ @Component public class EkJwtAuthorizationTokenFilter extends OncePerRequestFilter { @Value("${jwt.token_header}") private String EK_TOKEN_HEADER; @Value("${jwt.token_prefix}") private String EK_TOKEN_PREFIX; @Autowired private EkJwtTokenUtil jwtTokenUtil; @Autowired private IEkUserService userService; @Override protected void doFilterInternal( HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException { String authHeader = httpServletRequest.getHeader(this.EK_TOKEN_HEADER); if (StringUtils.isNotEmpty(authHeader) && authHeader.startsWith(this.EK_TOKEN_PREFIX)){ final String authToken = StringUtils.substring(authHeader, this.EK_TOKEN_PREFIX.length()); String logName = StringUtils.isNoneEmpty(authToken) ? jwtTokenUtil.getUsernameFromToken(authToken) : null; if (StringUtils.isNotEmpty(logName) && SecurityContextHolder.getContext().getAuthentication() == null){ EkUser user = userService.selectByLogName(logName); EkUserDetails userDetails = new EkUserDetails(); userDetails.setPassword(user.getPassWord()); userDetails.setLoginName(user.getLogName()); userDetails.setUserName(user.getUserName()); userDetails.setUserId(StringUtils.join(user.getId())); if (jwtTokenUtil.validateToken(authToken, userDetails)){ UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( userDetails, null, userDetails.getAuthorities() ); SecurityContextHolder.getContext().setAuthentication(authentication); } } } filterChain.doFilter(httpServletRequest, httpServletResponse); } }
三、在二的基础上只修改securityconfig配置类即可
package com.ek.security.config; import com.ek.security.EkUserDetailsService; import com.ek.security.handler.EkAuthenticationEntryPoint; import com.ek.security.handler.EkAuthenticationFailureHandler; import com.ek.security.handler.EkAuthenticationSuccessHandler; import com.ek.security.handler.EkPasswordEncoder; import com.ek.security.jwt.EkJwtAuthorizationTokenFilter; import com.ek.security.jwt.EkJwtTokenUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; import org.springframework.security.config.http.SessionCreationPolicy; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.crypto.password.PasswordEncoder; import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; @EnableWebSecurity public class EkMultiSecurityConfig { @Autowired private EkUserDetailsService userDetailsService; @Autowired private EkAuthenticationEntryPoint authenticationEntryPoint; @Autowired private EkAuthenticationFailureHandler authenticationFailureHandler; @Autowired private EkAuthenticationSuccessHandler authenticationSuccessHandler; @Autowired private EkPasswordEncoder passwordEncoder; @Configuration @Order(1) public class ApiSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private EkJwtAuthorizationTokenFilter jwtAuthorizationTokenFilter; @Override protected void configure(HttpSecurity http) throws Exception { http.antMatcher("/api/**") //<= Security only available for /api/** .authorizeRequests() .antMatchers("/api/register").permitAll() .antMatchers("/api/login").permitAll() .antMatchers("/api/public").permitAll() .antMatchers("/api/lost").permitAll() .anyRequest().authenticated() .and() .formLogin() .failureHandler(authenticationFailureHandler) .and() .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) .and() .addFilterBefore(jwtAuthorizationTokenFilter, UsernamePasswordAuthenticationFilter.class) ; } } @Configuration public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { // 添加自定义认证 auth .userDetailsService(userDetailsService) .passwordEncoder(passwordEncoder) ; } @Override protected void configure(HttpSecurity http) throws Exception { // http.authorizeRequests().antMatchers("/**").permitAll(); http.csrf().disable() // .and() .httpBasic().authenticationEntryPoint(authenticationEntryPoint) .and() .authorizeRequests() .antMatchers("/", "/index", "/toLogin", "/fail", "/druid/**").permitAll() .antMatchers("/resources/**").permitAll() .anyRequest().authenticated() // .access("@rbacauthorityservice.hasPermission(request,authentication)") // RBAC 动态 url 认证 .and() .formLogin().loginPage("/index") //指定自己的登录页面 .loginProcessingUrl("/toLogin") .usernameParameter("logName") .passwordParameter("password") .defaultSuccessUrl("/success", false) .failureHandler(authenticationFailureHandler) // .successHandler(authenticationSuccessHandler) .and() .logout() ; } } }
用到的其他类
@RestController @RequestMapping("/users") public class EkUserController { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private IEkUserService ekUserService; @RequestMapping(value = "", method = RequestMethod.GET) public JsonMsg getEkUserList(){ log.info("--------------------列表--------------------------------"); JsonMsg jsonMsg = new JsonMsg(); List<EkUser> list = ekUserService.selectUserList(new HashMap<>()); jsonMsg.setCode(200); jsonMsg.setMsg("success"); jsonMsg.setData(list); return jsonMsg; } }
@RestController public class LoginController { private Logger log = LoggerFactory.getLogger(this.getClass()); @Autowired private IEkUserService ekUserService; @RequestMapping(value = {"", "/index"}) public ModelAndView index(){ log.info("--------------------首页--------------------------------"); return new ModelAndView("index"); } @RequestMapping(value = "/fail") public ModelAndView fail(){ log.info("--------------------fail--------------------------------"); return new ModelAndView("fail"); } @RequestMapping(value = "/toLogin", method = RequestMethod.POST) public ModelAndView toLogin(){ log.info("--------------------toLogin--------------------------------"); return new ModelAndView("success"); } @RequestMapping(value = "/success") public ModelAndView success(){ log.info("--------------------success--------------------------------"); return new ModelAndView("success"); } }
说明:
关于druid监控登录的问题,我把它放到了下面这个地方,网上查资料说是添加http.csrf().ignoringAntMatchers("/druid/*")就行,但是我添加后并没有成功。
.antMatchers("/", "/index", "/toLogin", "/fail", "/druid/**").permitAll()