Spring Security教程(13)---- 验证码功能的实现

有三中方法可以实现验证码的功能

第一种是自定义一个filter,放在SpringSecurity过滤器之前,在用户登录的时候会先经过这个filter,然后在这个filter中实现对验证码进行验证的功能,这种方法不推荐,因为它已经脱离了SpringSecurity

第二种是自定义一个filter让它继承自UsernamePasswordAuthenticationFilter,然后重写attemptAuthentication方法在这个方法中实现验证码的功能,如果验证码错误就抛出一个继承自AuthenticationException的验证吗错误的异常比如(CaptchaException),然后这个异常就会被SpringSecurity捕获到并将异常信息返回到前台,这种实现起来比较简单

  1. @Override  
  2. public Authentication attemptAuthentication(HttpServletRequest request,  
  3.         HttpServletResponse response) throws AuthenticationException {  
  4.       
  5.     String requestCaptcha = request.getParameter(this.getCaptchaFieldName());  
  6.     String genCaptcha = (String)request.getSession().getAttribute("code");  
  7.       
  8.     logger.info("开始校验验证码,生成的验证码为:"+genCaptcha+" ,输入的验证码为:"+requestCaptcha);  
  9.       
  10.     if( !genCaptcha.equals(requestCaptcha)){  
  11.         throw new CaptchaException(  
  12.                 this.messageSource.getMessage("AbstractUserDetailsAuthenticationProvider.badCaptcha",null,"Default",null));  
  13.     }  
  14.     return super.attemptAuthentication(request, response);  
  15. }  
然后在配置文件中配置下
  1. <bean id="loginFilter" class="com.zrhis.system.security.DefaultUsernamePasswordAuthenticationFilter">  
  2.     <property name="authenticationManager"  ref="authenticationManager"></property>  
  3.     <property name="authenticationSuccessHandler">  
  4.         <bean class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">  
  5.             <property name="defaultTargetUrl" value="/index.jsp"></property>  
  6.         </bean>  
  7.     </property>  
  8.     <property name="authenticationFailureHandler">  
  9.         <bean class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">  
  10.             <property name="defaultFailureUrl" value="/login.jsp"></property>  
  11.         </bean>  
  12.     </property>  
  13. </bean>  
最后在http中加入custom-filter配置,将这个filter放在SpringSecurity的FORM_LOGIN_FILTER之前
  1. <custom-filter ref="loginFilter" before="FORM_LOGIN_FILTER"/>  
最后一种是直接替换掉SpringSecurity的UsernamePasswordAuthenticationFilter,这种比较复杂,但是更为合理,也是我现在正在用的。

如果用这种方法那么http 中的auto-config就必须去掉,而form-login配置也必须去掉,因为这个不需要了,里面的属性都需要我们自行注入。

首先需要创建一个EntryPoint

  1. <bean id="authenticationEntryPoint" class="org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint">  
  2.     <property name="loginFormUrl" value="/login.jsp" />  
  3. </bean>  
然后在http中配置下
  1. <sec:http access-decision-manager-ref="accessDecisionManager"  
  2.         entry-point-ref="authenticationEntryPoint">  
然后我们来写CaptchaAuthenticationFilter,同样需要继承自UsernamePasswordAuthenticationFilter
  1. public class CaptchaAuthenticationFilter extends UsernamePasswordAuthenticationFilter{  
  2.       
  3.     public static final String SPRING_SECURITY_FORM_CAPTCHA_KEY = "j_captcha";  
  4.     public static final String SESSION_GENERATED_CAPTCHA_KEY = Constant.SESSION_GENERATED_CAPTCHA_KEY;  
  5.       
  6.     private String captchaParameter = SPRING_SECURITY_FORM_CAPTCHA_KEY;  
  7.       
  8.     public Authentication attemptAuthentication(HttpServletRequest request,  
  9.             HttpServletResponse response) throws AuthenticationException {  
  10.           
  11.         String genCode = this.obtainGeneratedCaptcha(request);  
  12.         String inputCode = this.obtainCaptcha(request);  
  13.         if(genCode == null)  
  14.             throw new CaptchaException(this.messages.getMessage("LoginAuthentication.captchaInvalid"));  
  15.         if(!genCode.equalsIgnoreCase(inputCode)){  
  16.             throw new CaptchaException(this.messages.getMessage("LoginAuthentication.captchaNotEquals"));  
  17.         }  
  18.           
  19.         return super.attemptAuthentication(request, response);  
  20.     }  
  21.       
  22.     protected String obtainCaptcha(HttpServletRequest request){  
  23.         return request.getParameter(this.captchaParameter);  
  24.     }  
  25.       
  26.     protected String obtainGeneratedCaptcha (HttpServletRequest request){  
  27.         return (String)request.getSession().getAttribute(SESSION_GENERATED_CAPTCHA_KEY);  
  28.     }  
  29.       
  30. }  
在配置文件中配置CaptchaAuthenticationFilter
  1. <bean id="captchaAuthenticaionFilter" class="com.zrhis.system.security.CaptchaAuthenticationFilter">  
  2.     <property name="authenticationManager" ref="authenticationManager" />  
  3.     <property name="authenticationFailureHandler" ref="authenticationFailureHandler" />  
  4.     <property name="authenticationSuccessHandler" ref="authenticationSuccessHandler" />  
  5.     <property name="filterProcessesUrl" value="/login.do" />  
  6. </bean>  
  7.   
  8. <bean id="authenticationSuccessHandler" class="com.zrhis.system.security.SimpleLoginSuccessHandler">  
  9.     <property name="defaultTargetUrl" value="/WEB-INF/app.jsp"></property>  
  10.     <property name="forwardToDestination" value="true"></property>  
  11. </bean>  
  12. <bean id="authenticationFailureHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">  
  13.     <property name="defaultFailureUrl" value="/login.jsp" />  
  14. </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中完整的配置就变成了下面的内容

  1. <sec:http access-decision-manager-ref="accessDecisionManager"  
  2.     entry-point-ref="authenticationEntryPoint">  
  3.       
  4.     <sec:access-denied-handler ref="accessDeniedHandler"/>  
  5.       
  6.     <sec:session-management invalid-session-url="/login.jsp" />  
  7.       
  8.     <sec:custom-filter ref="filterSecurityInterceptor" before="FILTER_SECURITY_INTERCEPTOR"/>  
  9.     <sec:custom-filter ref="captchaAuthenticaionFilter" position="FORM_LOGIN_FILTER"/>  
  10. </sec:http>  

custom-filter中before是在这个filter之前,after是之后,position是替换。

这样就可以实现对验证码的验证了,效果如下


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring Security可以通过自定义过滤器来实现验证码登录,主要步骤如下: 1. 添加依赖 在pom.xml文件中添加以下依赖: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency> <dependency> <groupId>com.google.code.kaptcha</groupId> <artifactId>kaptcha</artifactId> <version>2.3.2</version> </dependency> ``` 2. 配置验证码生成器 在Spring Security的配置类中定义验证码生成器: ```java @Bean public DefaultKaptcha kaptcha() { Properties properties = new Properties(); properties.setProperty("kaptcha.border", "no"); properties.setProperty("kaptcha.textproducer.font.color", "black"); properties.setProperty("kaptcha.image.width", "150"); properties.setProperty("kaptcha.image.height", "50"); properties.setProperty("kaptcha.textproducer.char.length", "4"); Config config = new Config(properties); DefaultKaptcha defaultKaptcha = new DefaultKaptcha(); defaultKaptcha.setConfig(config); return defaultKaptcha; } ``` 3. 定义验证码过滤器 创建一个验证码过滤器类,继承`OncePerRequestFilter`,重写`doFilterInternal`方法,在其中判断是否需要验证验证码,如果是则验证并抛出异常。 ```java public class CaptchaFilter extends OncePerRequestFilter { private final static String CAPTCHA_SESSION_KEY = "captcha_key"; private final static String LOGIN_URL = "/login"; @Autowired private DefaultKaptcha kaptcha; @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { if (LOGIN_URL.equals(request.getRequestURI()) && request.getMethod().equalsIgnoreCase("post")) { try { validate(request); } catch (CaptchaException e) { request.setAttribute("errorMessage", e.getMessage()); request.getRequestDispatcher("/login").forward(request, response); return; } } filterChain.doFilter(request, response); } private void validate(HttpServletRequest request) throws CaptchaException { String captchaCode = request.getParameter("captchaCode"); String captchaSession = (String) request.getSession().getAttribute(CAPTCHA_SESSION_KEY); if (StringUtils.isEmpty(captchaCode) || StringUtils.isEmpty(captchaSession) || !captchaCode.equalsIgnoreCase(captchaSession)) { throw new CaptchaException("验证码错误"); } } } ``` 其中`CaptchaException`为自定义异常类,用于抛出验证码校验失败的异常信息。 4. 注册验证码过滤器 将验证码过滤器注册到Spring Security的配置中: ```java @Override protected void configure(HttpSecurity http) throws Exception { http.addFilterBefore(new CaptchaFilter(), UsernamePasswordAuthenticationFilter.class) .authorizeRequests() .antMatchers("/login", "/captcha").permitAll() .anyRequest().authenticated() .and() .formLogin().loginPage("/login").defaultSuccessUrl("/index") .and() .logout().logoutSuccessUrl("/login").permitAll() .and() .csrf().disable(); } ``` 其中,`addFilterBefore`方法用于将验证码过滤器添加到Spring Security的过滤器链中。 5. 添加验证码生成接口 在控制器中添加一个生成验证码的接口,用于获取验证码图片和将验证码存储到session中: ```java @GetMapping("/captcha") public void captcha(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setHeader("Cache-Control", "no-store, no-cache"); response.setContentType("image/jpeg"); String captchaText = kaptcha.createText(); BufferedImage captchaImage = kaptcha.createImage(captchaText); request.getSession().setAttribute(CAPTCHA_SESSION_KEY, captchaText); ServletOutputStream outputStream = response.getOutputStream(); ImageIO.write(captchaImage, "jpg", outputStream); IOUtils.closeQuietly(outputStream); } ``` 6. 修改登录页面 在登录页面中添加一个输入框和验证码图片: ```html <form method="post" action="/login"> <div class="form-group"> <label for="username">用户名</label> <input type="text" class="form-control" id="username" name="username" placeholder="请输入用户名"> </div> <div class="form-group"> <label for="password">密码</label> <input type="password" class="form-control" id="password" name="password" placeholder="请输入密码"> </div> <div class="form-group"> <label for="captchaCode">验证码</label> <div class="input-group"> <input type="text" class="form-control" id="captchaCode" name="captchaCode" placeholder="请输入验证码"> <div class="input-group-append"> <img src="/captcha" onclick="this.src='/captcha?'+Math.random()" style="cursor:pointer;"> </div> </div> </div> <button type="submit" class="btn btn-primary">登录</button> </form> ``` 以上就是Spring Security实现验证码登录的步骤。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值