弹簧安全验证通过过滤器验证码有错误的值
问题描述:
我正在使用弹簧安全进行身份验证登录的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">
</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>