弹簧安全验证通过过滤器验证码有错误的值

问题描述:

我正在使用弹簧安全进行身份验证登录的Spring Boot。我完成了这部分。现在,我想在登录页面中实现验证码。我做到了,但有时候价值出错了。这里是我的源代码。弹簧安全验证通过过滤器验证码有错误的值

登录页面

<form th:action="@{/j_spring_security_check}" method="post"> 
<tr> 
       <th align="left" width="30%"> 
        <label for="userId">User Id</label> 
       </th> 
       <td width="70%"> 

        <input type="text" style="width: 150px" name="userId" autocomplete="off"/> 
       </td> 
      </tr> 
      <tr> 
       <th align="left" width="30%"> 
        Password 
       </th> 
       <td width="70%"> 

        <input type="PASSWORD" style="width: 150px" name="password" autocomplete="off"/> 
       </td> 
      </tr> 
      <tr> 
       <th align="left" width="30%"> 
        Answer 
       </th> 
       <td width="70%"> 
        <input type="text" name="logonAnswer" style="width: 150px"/> 
       </td> 
      </tr> 
      <tr> 
       <td align="right">&nbsp; 
       </td> 
       <td align="left"> 
        <div id="captcha" 
         style="cursor: pointer; height: 30px; width: 150px; display: inline-block; float: left"><img 
          th:src="@{/captcha}"/></div> 
        <div id="captchaRefresh" class="refresh-btn" title="Click to get other Captcha"></div> 
       </td> 
      </tr> 
</form> 

在安全配置

@Configuration 
@EnableWebSecurity 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private UserDetailsService userDetailsService; 
    @Autowired 
    private AccessDeniedHandler accessDeniedHandler; 
    @Autowired 
    private RoleRepository roleRepository; 
    @Autowired 
    private CaptchaFilter captchaFilter; 

    @Autowired 
    private PasswordEncoder passwordEncoder() { 
     return new CustomerPasswordEncoder(); 
    } 

    @Autowired 
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { 
     auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder()); 
    } 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
       .authorizeRequests() 
       .antMatchers("/register").permitAll() 
       .antMatchers("/configuration/**").hasRole(roleRepository.getRolesByGroup("USER")) 
       .antMatchers("/configuration/**", "/merchant/**", "/import/**", "/manualSettle/**", "/report/**", "/user/**").hasAnyRole(roleRepository.getRolesByGroup("ADMIN")) 
       .antMatchers("/superadmin").hasRole(roleRepository.getRolesByGroup("SUPERADMIN")) 
       .and() 
       .formLogin() 
       .loginPage("/login") 
       .loginProcessingUrl("/j_spring_security_check") 
       .usernameParameter("userId") 
       .passwordParameter("password") 
       .defaultSuccessUrl("/") 
       .failureUrl("/login?error") 
       .and() 
       .addFilterBefore(captchaFilter, UsernamePasswordAuthenticationFilter.class) 
       .exceptionHandling().accessDeniedHandler(accessDeniedHandler); 
    } 
} 

在验证码验证过滤

@Autowired 
    UserDetailsServiceImpl userDetailsService; 

    @Override 
    public void init(FilterConfig filterConfig) throws ServletException { 

    } 

    @Override 
    public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     HttpServletRequest request = (HttpServletRequest) req; 
     HttpSession session = request.getSession(false); 
     if (userDetailsService != null 
       && request.getParameter("logonAnswer") != null 
       && !request.getParameter("logonAnswer").equals("") 
       && session != null && request.getParameter("logonAnswer").equalsIgnoreCase(session.getAttribute("wirecardmposcaptcha").toString())) { 
      userDetailsService.setCaptchaOK(true); 
     } 

     chain.doFilter(request, response); 
    } 

而在userDetailsImplement

private boolean captchaOK; 

    public void setCaptchaOK(boolean captchaOK) { 
     this.captchaOK = captchaOK; 
    } 

    @Override 
    @Transactional 
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { 
     Users user = userRepository.findByUserId(username); 
     if (user == null) { 
      throw new UsernameNotFoundException("UserId or Password invalid"); 
     } 

     if (!captchaOK) 
      throw new InternalAuthenticationServiceException("Invalid Captcha"); 

     Set<GrantedAuthority> grantedAuthorities = new HashSet<>(); 
     Set<Roles> roles = user.getRoles(); 
     for (Roles role : roles) { 
      grantedAuthorities.add(new SimpleGrantedAuthority(role.getRoleName())); 
     } 

     return new org.springframework.security.core.userdetails.User(user.getUserId(), user.getPassword(), user.getEnabled().equals("true"), true, true, true, grantedAuthorities); 
    } 

所以在登录控制器:

private String getErrorMessage(HttpServletRequest request, String key) { 

     Exception exception = (Exception) request.getSession().getAttribute(key); 

     String error = ""; 
     if (exception instanceof BadCredentialsException) { 
      error = "Invalid user ID and password!"; 
     } else if (exception instanceof DisabledException) { 
      error = "User is locked"; 
     } else if (exception instanceof InternalAuthenticationServiceException) { 
      error = "Invalid answer."; 
     } else { 
      error = "Invalid user ID and password!"; 
     } 

     return error; 
    } 

所以,我调试验证码过滤captchaOk的值更改了很多次。我不知道我是否正确地做了。

请看看它并给予意见。

谢谢。

我定制了一个过滤器来验证Spring引导应用程序中的验证码。可能你的定制过滤器有问题。你可以参考我的实现:

1.CaptchaAuthenticationFilter:创建它时将验证码放在会话中,然后从会话中取出来验证。

import org.springframework.security.authentication.InsufficientAuthenticationException; 
import org.springframework.security.core.Authentication; 
import org.springframework.security.core.AuthenticationException; 
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; 
import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler; 

import javax.servlet.FilterChain; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
import java.io.IOException; 

/** 
* The filter to verify captcha. 
*/ 
public class CaptchaAuthenticationFilter extends AbstractAuthenticationProcessingFilter { 

    private String processUrl; 

    public CaptchaAuthenticationFilter(String defaultFilterProcessesUrl, String failureUrl) { 
     super(defaultFilterProcessesUrl); 
     this.processUrl = defaultFilterProcessesUrl; 
     setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler(failureUrl)); 
    } 

    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { 
     HttpServletRequest req = (HttpServletRequest) request; 
     HttpServletResponse res=(HttpServletResponse)response; 
     if(processUrl.equals(req.getServletPath()) && "POST".equalsIgnoreCase(req.getMethod())){ 
      String expect = req.getSession().getAttribute("YZM").toString(); 

      //remove from session 
      req.getSession().removeAttribute("YZM"); 

      if (expect != null && !expect.equals(req.getParameter("verifyCode"))){ 
       unsuccessfulAuthentication(req, res, new InsufficientAuthenticationException("Wrong verification code.")); 
       return; 
      } 
     } 
     chain.doFilter(request, response); 
    } 

    @Override 
    public Authentication attemptAuthentication(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws AuthenticationException, IOException, ServletException { 
     return null; 
    } 
} 

2.Configure它弹安全:

@Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http.csrf().disable(); 
     // add filter here 
     http.addFilterBefore(new CaptchaAuthenticationFilter("/login", "/login?error2"), UsernamePasswordAuthenticationFilter.class); 
     http.authorizeRequests() 
       .antMatchers("/").hasRole("USER") 
       .antMatchers("/index").hasRole("USER") 
       .antMatchers("/message/*").hasRole("USER") 
       .anyRequest().permitAll() 
       .and().formLogin().loginPage("/login").defaultSuccessUrl("/index").failureUrl("/login?error1").permitAll() 
       .and().rememberMe().tokenValiditySeconds(60*60*7).key("message") 
       .and().logout().logoutUrl("/logout").logoutSuccessUrl("/login").permitAll(); 
    } 

3.Note的failureUrl /login?error2上方。如果验证码验证失败,则请求将在那里重定向。您可以在页面上捕获错误,如下所示:

<div class="clearfix"> 
    <div th:if="${param.error1}"> 
     <div class="btn btn-xs btn-danger"> 
      <i class="icon-bolt bigger-110"></i> 
      Wrong username or password! 
     </div> 
    </div> 

    <div th:if="${param.error2}"> 
     <div class="btn btn-xs btn-danger"> 
      <i class="icon-bolt bigger-110"></i> 
      Wrong verification code! 
     </div> 
    </div> 
</div>