添加登录验证码
在第 3 章中介绍了一种登录验证码的实现方案,我们通过学习了 Spring Security 的过滤器链之后,可能也会发现,使用过滤虑器链来实现登录验证码更加容易。这里就介绍一下使用过滤器实现验证码的方案。
验证码的生成方案依然和 3.3 节中的一致,这里不再述,主要介绍一下 LoginFilter 的定义以及配置。先来看 LoginFilter 的定义:
public class LoginFilter extends UsernamePasswordAuthenticationFilter {
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
if (!request.getMethod().equals("POST")) {
throw new AuthenticationServiceException(
"Authentication method not supported: " + request.getMethod());
}
String kaptcha = request.getParameter("kaptcha");
String sessionKaptcha = (String) request.getSession().getAttribute("kaptcha");
if (!StringUtils.isEmpty(kaptcha) && !StringUtils.isEmpty(sessionKaptcha) && kaptcha.equalsIgnoreCase(sessionKaptcha)) {
return super.attemptAuthentication(request, response);
}
throw new AuthenticationServiceException("验证码输入错误");
}
}
在 LoginFilter 中首先判断验证码是否正确,如果验证码输入错误,则直接抛出异常;如果验证码输入正确,则调用父类的 attemptAuthentication 方法进行登录校验。接下来,在 SecurityConfig 中配置 LoginFilter:
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth)
throws Exception {
auth.inMemoryAuthentication()
.withUser("javaboy")
.password("{noop}123")
.roles("admin");
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean()
throws Exception {
return super.authenticationManagerBean();
}
@Bean
LoginFilter loginFilter() throws Exception {
LoginFilter loginFilter = new LoginFilter();
loginFilter.setFilterProcessesUrl("/doLogin");
loginFilter.setAuthenticationManager(authenticationManagerBean());
loginFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/hello"));
loginFilter.setAuthenticationFailureHandler(new SimpleUrlAuthenticationFailureHandler("/mylogin.html"));
return loginFilter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/vc.jpg").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/mylogin.html")
.permitAll()
.and()
.csrf().disable();
http.addFilterAt(loginFilter(),
UsernamePasswordAuthenticationFilter.class);
}
}
这里的配置基本和 4.6 节中的配置一致。不同的是,我们修改了登录请求的处理地址,注意这个地址要在 LoginFilter 实例上配置。
这里介绍的第二种添加登录验证码的方式,相比于第一种方式,这种验证码的添加方式更简单也更易于理解。