1. Spring Security大局观
以下内容基于Servlet应用进行分析。首先通过官方的Spring Security在基于Servlet应用的架构图,了解下请求是如何到达Spring Security的。

Spring在Filter Chain中加入DelegatingFilterProxy过滤器;DelegatingFilterProxy将所有请求委托给FilterChainProxy;FilterChainProxy根据请求调用合适的SecurityFilterChain。
DelegatingFilterProxy: Spring提供的一个Filter实现,其作用是将所有请求委托给一个由Spring容器管理的Filter Bean。FilterChainProxy: Spring Security提供的Filter,通常被包装在DelegatingFilterProxy中;它将过滤器请求委托给 Spring 管理的过滤器 bean 列表。SecurityFilterChain: 定义能够与HttpServletRequest匹配的过滤器链。FilterChainProxy使用SecurityFilterChain来确定应为请求调用哪些Spring Security过滤器。
2. 简述Security Filter
Spring Security内置了一些Filter,这些Filter被称为Security Filter。Security Filter通过SecurityFilterChain插入到FilterChainProxy。下面介绍一些Filter:
UsernamePasswordAuthenticationFilter: 用于处理基于表单提交的用户和密码认证过滤器;AnonymousAuthenticationFilter: 匿名认证过滤器,在Spring Security中,所有对资源的访问都要有Authentication,使用匿名身份访问不需要认证的资源;RememberMeAuthenticationFilter: 用于处理 记住我 功能的过滤器;SessionManagementFilter: 用于管理session的过滤器;ConcurrentSessionFilter: 并发session处理过滤器,主要有两个功能判断session是否过期和更新最新的访问时间。- …
2.1 AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter是Spring Security用于处理认证请求的抽象Security Filter。AbstractAuthenticationProcessingFilter通过requiresAuthenticationRequestMatcher属性来指定需要身份认证的请求,如果请求与requiresAuthenticationRequestMatcher匹配,就拦截请求并尝试进行身份认证。
AbstractAuthenticationProcessingFilter要求必须设置authenticationManager属性,因为它需要AuthenticationManager来完成身份认证请求。
AbstractAuthenticationProcessingFilter中身份认证由attemptAuthentication方法执行,该方法需要创建身份认证令牌,并调用AuthenticationManager来完成身份认证。
UsernamePasswordAuthenticationFilter是AbstractAuthenticationProcessingFilter的实现类,用于处理基于表单提交的认证请求,默认匹配/login请求。
UsernamePasswordAuthenticationFilter对attemptAuthentication方法的实现: 从HttpServletRequest中提取出username和password,并根据username和password创建UsernamePasswordAuthenticationToken实例,最后调用AuthenticationManager的authenticate方法进行认证。
UsernamePasswordAuthenticationToken是Authentication的一种实现,用于简单表示用户名和密码的请求令牌。
public class UsernamePasswordAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
public static final String SPRING_SECURITY_FORM_USERNAME_KEY = "username";
public static final String SPRING_SECURITY_FORM_PASSWORD_KEY = "password";
// 省略其他代码
@Override
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException {
if (this.postOnly && !request.getMethod().equals("POST")) {
throw new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
}
String username = obtainUsername(request);
username = (username != null) ? username : "";
username = username.trim();
String password = obtainPassword(request);
password = (password != null) ? password : "";
UsernamePasswordAuthenticationToken authRequest = new UsernamePasswordAuthenticationToken(username, password);
// Allow subclasses to set the "details" property
setDetails(request, authRequest);
return this.getAuthenticationManager().authenticate(authRequest);
}
protected String obtainUsername(HttpServletRequest request) {
return request.getParameter(this.usernameParameter);
}
// 省略其他代码
}
2.2 AuthenticationManager
AuthenticationManager是用于处理认证请求的接口,只声明了一个authenticate(Authentication)方法,该方法尝试对传递的Authentication对象进行身份验证,如果成功则返回一个完全填充的Authentication对象。
ProviderManager是一个常用的AuthenticationManager实现。ProviderManager有两个重要的属性List<AuthenticationProvider> providers和AuthenticationManager parent。
AuthenticationProvider用于针对不同Authentication进行具体的认证。例如DaoAuthenticationProvider针对UsernamePasswordAuthenticationToken进行认证。
为了文章篇幅简洁,这里简述下ProviderManager的处理逻辑,不进行代码展示:
- 首先通过循环
providers进行身份认证,直到得到非空响应(非空响应表示认证成功); - 当
providers前面的AuthenticationProvider出现了除AccountStatusException和InternalAuthenticationServiceException之外的异常,会使用lastException变量记录异常,然后遍历下一个AuthenticationProvider进行认证;如果后续的AuthenticationProvider认证成功,则忽略前面的异常。 - 如果
providers中的AuthenticationProvider都认证失败,且指定了parent,则使用parent进行认证。
3. 认证过程
- 在Spring Security中,当前请求到达
DelegatingFilterProxy时,DelegatingFilterProxy会调用FilterChainProxy的doFilter方法来处理请求; FilterChainProxy先从filterChains集合中获取匹配请求的SecurityFilterChain,接着调用SecurityFilterChain的getFilters方法获得Filter集合;最后以Filter Chain方式执行Filter集合;- 当执行到
UsernamePasswordAuthenticationFilter,且是/login请求时,则开始尝试进行认证处理。先从HttpServletRequest中提取username和password,并根据username和password构建UsernamePasswordAuthenticationToken; - 接着将
UsernamePasswordAuthenticationToken作为AuthenticationManager的authenticate方法的参数,UsernamePasswordAuthenticationFilter默认使用ProviderManager实例; ProviderManager首先通过循环providers集合进行身份认证,如果providers集合都认证失败,就尝试交给parent进行认证;如果认证成功,则返回一个新的Authentication;- 如果认证成功,
UsernamePasswordAuthenticationFilter将新的Authentication存放到当前当前线程的SecurityContext中;发布InteractiveAuthenticationSuccessEvent事件;进行RememberMe处理;调用AuthenticationSuccessHandler; - 如果认证失败,如果身份验证失败,它将委托给配置的
AuthenticationFailureHandler以允许将失败信息传达给客户端。 默认实现是SimpleUrlAuthenticationFailureHandler,它向客户端发送 401 错误代码。
本文深入解析了Spring Security的架构和过滤器链,包括DelegatingFilterProxy、FilterChainProxy和SecurityFilterChain的角色。重点介绍了AbstractAuthenticationProcessingFilter和UsernamePasswordAuthenticationFilter在表单认证中的作用,以及AuthenticationManager和ProviderManager的认证逻辑。当请求到达Spring Security时,经过一系列过滤器处理,最终通过UsernamePasswordAuthenticationFilter进行身份验证,利用AuthenticationManager进行认证,成功后将Authentication存入SecurityContext,并处理RememberMe和AuthenticationSuccessHandler等后续操作。
3495

被折叠的 条评论
为什么被折叠?



