如何验证提交上面的验证码,之前扩展自定义登录的时候都是实现的spring的接口
但是spring并没有提供实现了一个接口就能实现验证码校验
spring security就是一条过滤器链,我们可以在这条链中加入自己写的过滤器
在这里加一个自己写的过滤器 对应的校验逻辑是在该过滤器中完成
验证通过再进入后面的过滤器 验证不过就抛异常
验证码过滤器类
public class ValidateCodeFilter extends OncePerRequestFilter {//spring提供的,保证在一个请求中只会被调用一次 private SessionStrategy sessionStrategy = new HttpSessionSessionStrategy(); private AuthenticationFailureHandler failureHandler; public AuthenticationFailureHandler getFailureHandler() { return failureHandler; } public void setFailureHandler(AuthenticationFailureHandler failureHandler) { this.failureHandler = failureHandler; } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException { if(StringUtils.equals(request.getRequestURI(),"/authentication/form") &&StringUtils.endsWithIgnoreCase(request.getMethod(),"post")){//判断请求 try{ validate(request); }catch(ValidateCodeException e){ failureHandler.onAuthenticationFailure(request,response,e);//交给错误处理器 return; } } chain.doFilter(request,response); } public void validate(HttpServletRequest request) throws ServletRequestBindingException {//校验逻辑在这个方法内 ServletWebRequest req = new ServletWebRequest(request); ImageCode codeInSession = (ImageCode) sessionStrategy.getAttribute(req,ValidateCodeController.SESSION_KEY); String codeInRequest = ServletRequestUtils.getStringParameter(request,"imageCode"); if(StringUtils.isBlank(codeInRequest)){ throw new ValidateCodeException("验证码不能为空"); } if(codeInSession==null){ throw new ValidateCodeException("验证码不存在"); } if(codeInSession.isExpire()){ sessionStrategy.removeAttribute(req,ValidateCodeController.SESSION_KEY); throw new ValidateCodeException("验证码已过期"); } if(!StringUtils.equals(codeInSession.getCode(),codeInRequest)){ throw new ValidateCodeException("验证码不匹配"); } sessionStrategy.removeAttribute(req,ValidateCodeController.SESSION_KEY); } } 配置 protected void configure(HttpSecurity http) throws Exception { ValidateCodeFilter validateCodeFilter = new ValidateCodeFilter(); validateCodeFilter.setFailureHandler(playmakerAuthenticationFailureHandler);//设置失败处理器 http.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)//设置这个过滤器在这个过滤器之前执行 .formLogin()//form表单 高版本中默认是表单 低版本中默认是HttpBasic .loginPage("/authentication/require") //指定登录页面的url .loginProcessingUrl("/authentication/form") //指定处理登录请求的url .successHandler(playmakerAuthenticationSuccessHandler) .failureHandler(playmakerAuthenticationFailureHandler) //httpBasic() //httpBasic .and() //对请求授权配置 .authorizeRequests() .antMatchers("/playmaker-signIn.html", "/authentication/require", "/error", "/code/image", securityProperties.getBrowser().getLoginPage()).permitAll()//当访问这些url时不需要身份认证 .anyRequest()//对任意请求都必须是已认证才能访问 .authenticated() .and() .csrf().disable();//关闭csrf } 一旦抛出异常错误信息太多了 所以我们只让其返回错误的消息注意要把LoginType改成json @Component("playmakerAuthenticationFailureHandler") public class PlaymakerAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler {//这是spring security默认的失败处理器 处理方式是跳转 private Logger logger = LoggerFactory.getLogger(getClass()); @Autowired private ObjectMapper objectMapper; @Autowired private SecurityProperties securityProperties; @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { logger.info("登录失败"); if(securityProperties.getBrowser().getLoginType().equals(LoginType.JSON)){ response.setContentType("application/json;charset=utf-8"); response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());//默认200 因为登录失败 所以设置为500 response.getWriter().write(objectMapper.writeValueAsString(new SimpleResponse(exception.getMessage())));//打印错误信息太多 只返回错误消息 } else{ super.onAuthenticationFailure(request,response,exception);//直接调用父类 } } }