貼工程目錄,其中bll目錄下是service+dao層,common是一些公用的模塊及功能類,web是controller層java
用到了druid及Redis,工具及配置類目錄(本文不介紹如何配置druid及Redis,可是我會把源文件放上)web
web文件目錄結構redis
接下來,說下大致的學習研究思路,在這塊我是分了三部分來作驗證的,這三部分只有securityconfig配置類有所區別spring
第一部分就是先後端不分離的security認證;apache
第二部是先後端分離,使用security+JWT認證;json
第三部分是一個項目中既包含前段的web驗證,也包含API的jwt認證;後端
1、第一部分的驗證:api
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登陸頁,登陸成功後再跳轉。
2、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); } }
3、在二的基礎上只修改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()