ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
有三中方法可以实现验证码的功能 第一种是自定义一个filter,放在SpringSecurity过滤器之前,在用户登录的时候会先经过这个filter,然后在这个filter中实现对验证码进行验证的功能,这种方法不推荐,因为它已经脱离了SpringSecurity 第二种是自定义一个filter让它继承自UsernamePasswordAuthenticationFilter,然后重写attemptAuthentication方法在这个方法中实现验证码的功能,如果验证码错误就抛出一个继承自AuthenticationException的验证吗错误的异常比如(CaptchaException),然后这个异常就会被SpringSecurity捕获到并将异常信息返回到前台,这种实现起来比较简单 ~~~ @Override public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { String requestCaptcha = request.getParameter(this.getCaptchaFieldName()); String genCaptcha = (String)request.getSession().getAttribute("code"); logger.info("开始校验验证码,生成的验证码为:"+genCaptcha+" ,输入的验证码为:"+requestCaptcha); if( !genCaptcha.equals(requestCaptcha)){ throw new CaptchaException( this.messageSource.getMessage("AbstractUserDetailsAuthenticationProvider.badCaptcha",null,"Default",null)); } return super.attemptAuthentication(request, response); } ~~~ 然后在配置文件中配置下 ~~~ <bean id="loginFilter" class="com.zrhis.system.security.DefaultUsernamePasswordAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManager"></property> <property name="authenticationSuccessHandler"> <bean class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler"> <property name="defaultTargetUrl" value="/index.jsp"></property> </bean> </property> <property name="authenticationFailureHandler"> <bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <property name="defaultFailureUrl" value="/login.jsp"></property> </bean> </property> </bean> ~~~ 最后在http中加入custom-filter配置,将这个filter放在SpringSecurity的FORM_LOGIN_FILTER之前 ~~~ <custom-filter ref="loginFilter" before="FORM_LOGIN_FILTER"/> ~~~ 最后一种是直接替换掉SpringSecurity的UsernamePasswordAuthenticationFilter,这种比较复杂,但是更为合理,也是我现在正在用的。 如果用这种方法那么http 中的auto-config就必须去掉,而form-login配置也必须去掉,因为这个不需要了,里面的属性都需要我们自行注入。 首先需要创建一个EntryPoint ~~~ <bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint"> <property name="loginFormUrl" value="/login.jsp" /> </bean> ~~~ 然后在http中配置下 ~~~ <sec:http access-decision-manager-ref="accessDecisionManager" entry-point-ref="authenticationEntryPoint"> ~~~ 然后我们来写CaptchaAuthenticationFilter,同样需要继承自UsernamePasswordAuthenticationFilter ~~~ public class CaptchaAuthenticationFilter extends UsernamePasswordAuthenticationFilter{ public static final String SPRING_SECURITY_FORM_CAPTCHA_KEY = "j_captcha"; public static final String SESSION_GENERATED_CAPTCHA_KEY = Constant.SESSION_GENERATED_CAPTCHA_KEY; private String captchaParameter = SPRING_SECURITY_FORM_CAPTCHA_KEY; public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException { String genCode = this.obtainGeneratedCaptcha(request); String inputCode = this.obtainCaptcha(request); if(genCode == null) throw new CaptchaException(this.messages.getMessage("LoginAuthentication.captchaInvalid")); if(!genCode.equalsIgnoreCase(inputCode)){ throw new CaptchaException(this.messages.getMessage("LoginAuthentication.captchaNotEquals")); } return super.attemptAuthentication(request, response); } protected String obtainCaptcha(HttpServletRequest request){ return request.getParameter(this.captchaParameter); } protected String obtainGeneratedCaptcha (HttpServletRequest request){ return (String)request.getSession().getAttribute(SESSION_GENERATED_CAPTCHA_KEY); } } ~~~ 在配置文件中配置CaptchaAuthenticationFilter ~~~ <bean id="captchaAuthenticaionFilter" class="com.zrhis.system.security.CaptchaAuthenticationFilter"> <property name="authenticationManager" ref="authenticationManager" /> <property name="authenticationFailureHandler" ref="authenticationFailureHandler" /> <property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" /> <property name="filterProcessesUrl" value="/login.do" /> </bean> <bean id="authenticationSuccessHandler" class="com.zrhis.system.security.SimpleLoginSuccessHandler"> <property name="defaultTargetUrl" value="/WEB-INF/app.jsp"></property> <property name="forwardToDestination" value="true"></property> </bean> <bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler"> <property name="defaultFailureUrl" value="/login.jsp" /> </bean> ~~~ 从配置文件中就可以看出来authenticationManager、authenticationFailureHandler、authenticationSuccessHandler、filterProcessesUrl等都需要我们自行注入了。 filterProcessesUrl定义的是登录验证的地址,默认的是j_spring_security_check这里我们改成login.do authenticationSuccessHandler中的defaultTargetUrl定义的是登录成功后跳转到的页面 authenticationFailureHandler中的defaultTargetUrl定义的是登录失败后跳转到的页面 我们的首页app.jsp在/WEB-INF下所以需要使用服务器跳转,所以需要将forwardToDestination设为true,因为客户端跳转是不能直接访问WEB-INF下的内容的。 最后在http中将FORM_LOGIN_FILTER替换掉,最终http中完整的配置就变成了下面的内容 ~~~ <sec:http access-decision-manager-ref="accessDecisionManager" entry-point-ref="authenticationEntryPoint"> <sec:access-denied-handler ref="accessDeniedHandler"/> <sec:session-management invalid-session-url="/login.jsp" /> <sec:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/> <sec:custom-filter ref="captchaAuthenticaionFilter" position="FORM_LOGIN_FILTER"/> </sec:http> ~~~ custom-filter中before是在这个filter之前,after是之后,position是替换。 这样就可以实现对验证码的验证了,效果如下 ![](https://box.kancloud.cn/2016-06-22_576a4b2970a57.jpg)