在验证用户名和密码之前,引入辅助验证可有效防范暴力试错,图形验证码就是简单且行之有效的一种辅助验证方式。下面将使用过滤器和自定义认证两种方式实现图形验证码功能。
一、使用过滤器实现图形验证码
验证码(CAPTCHA)的全称是 Completely Automated Public Turing test to tell Computers and Humans Apart,翻译过来就是 “全自动区分计算机和人类的图灵测试”。通俗地讲,验证码就是为了防止恶意用户暴力重试而设置的。不管是用户注册、用户登录,还是论坛发帖,如果不加以限制,一旦某些恶意用户利用计算机发起无限重试,就很容易使系统遭受破坏。
1.1 自定义过滤器:
在 Spring Security 中,实现验证码校验的方式有很多种,最简单的方式就是自定义一个专门处理验证码逻辑的过滤器,将其添加到 Spring Security 过滤器链的合适位置。当匹配到登录请求时,立刻对验证码进行校验,成功则放行,失败则提前结束整个验证请求。
说到 Spring Security 的过滤器,我们先回顾一下前面使用过的配置。
protected void configure(HttpSecurity http) throws Exception{
http.authorizeRequests().
antMatchers("/admin/api/**").hasRole("ADMIN").
antMatchers("/user/api/**").hasRole("USER").
antMatchers("/app/api/**").permitAll().
anyRequest().authenticated().
and().csrf().disable()
.formLogin()
.and()
.sessionManagement().maximumSessions(1);
}
HttpSecurity 实际上就是在配置 Spring Security 的过滤器链,诸如 CSRF、CORS、表单登录等,每个配置器对应一个过滤器。我们可以通过 HttpSecurity 配置过滤器的行为,甚至可以像 CRSF 一样直接关闭过滤器。例如,SessionManagement。
public SessionManagementConfigurer<HttpSecurity> sessionManagement() throws Exception {
return getOrApply(new SessionManagementConfigurer<HttpSecurity>());
}
Spring Security 通过 SessionManagementConfigurer 来配置 SessionManagement 的行为。与 SessionManagementConfigurer 类似的配置器还有 CorsConfigurer、RememberMeConfigurer 等,它们都实现了 SecurityConfigurer 的标准接口。
public interface SecurityConfigurer<O, B extends SecurityBuilder<O>> {
// 各个配置器的初始化方法
void init(B builder) throws Exception;
// 各个配置器被统一调用的配置方法
void configure(B builder) throws Exception;
}
SessionManagementConfigurer 是在 configure 方法中将最终的 SessionManagementFilter 插入过滤器链来实现会话管理的。
public void configure(H http) throws Exception {
SecurityContextRepository securityContextRepository = http
.getSharedObject(SecurityContextRepository.class);
// 初始化 SessionManagementFilter
SessionManagementFilter sessionManagementFilter = new SessionManagementFilter(
securityContextRepository, getSessionAuthenticationStrategy(http));
if (this.sessionAuthenticationErrorUrl != null) {
sessionManagementFilter.setAuthenticationFailureHandler(
new SimpleUrlAuthenticationFailureHandler(
this.sessionAuthenticationErrorUrl));
}
InvalidSessionStrategy strategy = getInvalidSessionStrategy();
if (strategy != null) {
sessionManagementFilter.setInvalidSessionStrategy(strategy);
}
AuthenticationFailureHandler failureHandler = getSessionAuthenticationFailureHandler();
if (failureHandler != null) {
sessionManagementFilter.setAuthenticationFailureHandler(failureHandler);
}
AuthenticationTrustResolver trustResolver = http
.getSharedObject(AuthenticationTrustResolver.class);
if (trustResolver != null) {
sessionManagementFilter.setTrustResolver(trustResolver);
}
sessionManagementFilter = postProcess(sessionManagementFilter);
// 将 SessionManagementFilter 添加到过滤器上
http.addFilter(sessionManagementFilter);
if (isConcurrentSessionControlEnabled()) {
ConcurrentSessionFilter concurrentSessionFilter = createConccurencyFilter(http);
concurrentSessionFilter = postProcess(concurrentSessionFilter);
http.addFilter(concurrentSessionFilter);
}
}
除 Spring Security 提供的过滤器外,我们还可以添加自己的过滤器以实现更多的安全功能,这些都可以在 HttpSecurity 中实现。
1.2 图形验证码过滤器:
毋庸置疑,要想实现图形验证码校验功能,首先应当有一个用于获取图形验证码的 API。绘制图形验证码的方法有很多,使用开源的验证码组件即可,例如 kaptcha。