AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter
AbstractAuthenticationProcessingFilter
是 Spring Security
中用于处理认证请求的一个非常重要的抽象类,它是大多数认证相关过滤器(例如,UsernamePasswordAuthenticationFilter
)的基类。这个过滤器的主要任务是接收认证请求,提取认证信息,交给 AuthenticationManager
进行认证,并在认证成功或失败时执行后续的处理。它是 Spring Security 中认证机制的核心组成部分。源码路径如下:
org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter
在 Spring Security 6.x 中,AbstractAuthenticationProcessingFilter
仍然是一个核心的抽象过滤器类,负责处理用户认证请求。与 Spring Security 5.x
版本相比,Spring Security 6.x
进行了许多更新和改进,但 AbstractAuthenticationProcessingFilter
的基本功能和使用方式仍然保持一致。它通常作为身份验证过滤器的基类,用于处理表单登录、基于 HTTP 头的身份验证等多种认证机制。
3.1、概述
AbstractAuthenticationProcessingFilter
是 org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter
的完整类名,它是 Spring Security 中用来处理认证请求的抽象类。这个过滤器负责拦截用户提交的认证请求(如表单登录请求),并从请求中提取认证信息,然后将这些信息交给 AuthenticationManager
进行认证。
在 Spring Security 6.x
中,这个类的核心功能并未发生太大变化,主要用于:
- 拦截认证请求;
- 提取认证信息;
- 调用
AuthenticationManager
进行认证; - 处理认证成功和失败的后续逻辑。
2、主要功能和工作流程
- 拦截认证请求:它会根据配置的 URL 模式拦截指定的请求路径。通常,这些请求会是提交登录表单的 POST 请求。
- 提取认证信息:该过滤器会从请求中提取用户认证信息(如用户名、密码等)。这些信息会被封装到
Authentication
对象中,常见的如UsernamePasswordAuthenticationToken
。 - 认证管理器认证:认证信息会被传递给
AuthenticationManager
进行验证,AuthenticationManager
会通过配置的AuthenticationProvider
进行认证。 - 认证结果处理:根据认证的结果:
- 成功:认证通过后,用户信息会被存储到
SecurityContext
中,使得后续的请求可以通过认证。 - 失败:认证失败时,可以配置不同的失败处理机制(如重定向到登录页面、返回错误信息等)
- 成功:认证通过后,用户信息会被存储到
3、关键方法详解
AbstractAuthenticationProcessingFilter
继承自 GenericFilterBean
,并实现了 Spring Security
的过滤器功能。其核心方法包括
doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
3.1 - 作用:这个方法是过滤器链中的核心,负责判断请求是否需要认证,并将请求交给认证管理器进行认证。
- 工作流程:
- 它首先通过
requiresAuthentication(request, response)
判断请求是否为需要认证的请求。 - 如果需要认证,它会调用
attemptAuthentication(request, response)
从请求中提取认证信息并尝试进行认证。 - 如果认证成功,它会把认证信息存储到
SecurityContext
中;如果认证失败,则调用失败处理方法unsuccessfulAuthentication(request, response, failed)
。
- 它首先通过
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
throws IOException, ServletException {
if (!requiresAuthentication(request, response)) {
chain.doFilter(request, response);
return;
}
try {
Authentication authenticationResult = attemptAuthentication(request, response);
if (authenticationResult == null) {
// return immediately as subclass has indicated that it hasn't completed
return;
}
this.sessionStrategy.onAuthentication(authenticationResult, request, response);
// Authentication success
if (this.continueChainBeforeSuccessfulAuthentication) {
chain.doFilter(request, response);
}
successfulAuthentication(request, response, chain, authenticationResult);
}
catch (InternalAuthenticationServiceException failed) {
this.logger.error("An internal error occurred while trying to authenticate the user.", failed);
unsuccessfulAuthentication(request, response, failed);
}
catch (AuthenticationException ex) {
// Authentication failed
unsuccessfulAuthentication(request, response, ex);
}
}
requiresAuthentication(HttpServletRequest request, HttpServletResponse response)
3.2 - 作用:用于判断当前请求是否需要认证,通常基于请求的 URL 或请求方法(如
POST
、GET
)进行判断。 - 默认实现:通常,
AbstractAuthenticationProcessingFilter
会通过 URL 匹配来判断是否需要认证。例如,UsernamePasswordAuthenticationFilter
会匹配登录请求 URL。
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
if (this.requiresAuthenticationRequestMatcher.matches(request)) {
return true;
}
if (this.logger.isTraceEnabled()) {
this.logger
.trace(LogMessage.format("Did not match request to %s", this.requiresAuthenticationRequestMatcher));
}
return false;
}
attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
3.3 作用:从请求中提取认证信息并将其封装为
Authentication
对象。通常,子类会重写此方法,根据具体的认证方式(如表单登录、OAuth 认证等)提取认证信息并创建相应的Authentication
对象。例如,在
UsernamePasswordAuthenticationFilter
中,attemptAuthentication
从请求中提取用户名和密码,封装成UsernamePasswordAuthenticationToken
,然后交给AuthenticationManager
进行认证。
public abstract Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException, ServletException;
successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult)
3.4、 - 作用:认证成功时调用。通常在这里可以将认证结果存储到
SecurityContext
中,允许后续的请求访问认证信息。 - 默认行为:在认证成功后,
SecurityContextHolder.getContext().setAuthentication(authResult)
会将认证信息存储到SecurityContext
中。
protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
Authentication authResult) throws IOException, ServletException {
SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
context.setAuthentication(authResult);
this.securityContextHolderStrategy.setContext(context);
this.securityContextRepository.saveContext(context, request, response);
if (this.logger.isDebugEnabled()) {
this.logger.debug(LogMessage.format("Set SecurityContextHolder to %s", authResult));
}
this.rememberMeServices.loginSuccess(request, response, authResult);
if (this.eventPublisher != null) {
this.eventPublisher.publishEvent(new InteractiveAuthenticationSuccessEvent(authResult, this.getClass()));
}
this.successHandler.onAuthenticationSuccess(request, response, authResult);
}
unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed)
3.5、 - 作用:认证失败时调用。可以在这里处理认证失败后的逻辑,例如跳转到登录失败页面、返回错误信息等。
- 默认行为:清除当前的
SecurityContext
,然后根据配置的AuthenticationFailureHandler
来处理失败的情况。
protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response,
AuthenticationException failed) throws IOException, ServletException {
this.securityContextHolderStrategy.clearContext();
this.logger.trace("Failed to process authentication request", failed);
this.logger.trace("Cleared SecurityContextHolder");
this.logger.trace("Handling authentication failure");
this.rememberMeServices.loginFail(request, response);
this.failureHandler.onAuthenticationFailure(request, response, failed);
}
4、运行流程
- 请求处理:当用户发送一个请求时,该请求会被发送到
AbstractAuthenticationProcessingFilter
。 - 尝试认证:
AbstractAuthenticationProcessingFilter
的doFilter
方法会调用其子类的attemptAuthentication
方法。- 在
attemptAuthentication
方法中,首先会获取请求参数,通常是用户名(username
)和密码(password
)。 - 接着,会创建一个
UsernamePasswordAuthenticationToken
对象,该对象保存了登录请求的参数,并且标记为未登录认证。
- 调用认证方法:
attemptAuthentication
方法会调用AuthenticationManager
的authenticate
方法,将UsernamePasswordAuthenticationToken
对象作为参数传递。AuthenticationManager
的实现类是ProviderManager
,它负责选择合适的AuthenticationProvider
进行认证。
- 认证过程:
ProviderManager
会遍历所有的AuthenticationProvider
,找到能够处理UsernamePasswordAuthenticationToken
的AuthenticationProvider
,通常是DaoAuthenticationProvider
。DaoAuthenticationProvider
会调用UserDetailsService
的loadUserByUsername
方法,根据用户名查询用户信息。- 接着,
DaoAuthenticationProvider
会进行前置检查(如用户是否已锁定、不可用、已过期)和密码检查(使用PasswordEncoder
的matches
方法判断密码是否正确)。 - 如果所有检查都通过,则认证成功,
ProviderManager
会创建一个新的UsernamePasswordAuthenticationToken
对象,表示认证成功,并包含用户的身份、凭证和权限列表。
- 处理认证结果:
- 如果认证成功,
ProviderManager
会隐藏Authentication
对象中的密码(数据脱敏),然后返回隐藏密码后的Authentication
对象。 UsernamePasswordAuthenticationFilter
的attemptAuthentication
方法执行结束后,会将结果交给父类的doFilter
方法。- doFilter方法会根据登录结果决定运行
successfulAuthentication
或unsuccessfulAuthentication
- 如果认证成功,会调用
AuthenticationSuccessHandler
处理认证成功后的操作,如重定向用户或生成自定义响应。 - 如果认证失败,会调用
AuthenticationFailureHandler
处理认证失败的情况,如生成适当的错误响应或执行自定义操作。
- 如果认证成功,会调用
- 如果认证成功,
5、常见子类
AbstractAuthenticationProcessingFilter
是一个抽象类,通常会被具体的认证过滤器继承和扩展。以下是一些常见的子类:
UsernamePasswordAuthenticationFilter
:- 用于处理传统的基于用户名和密码的表单认证。它会从 HTTP 请求的参数中提取用户名和密码,并将其封装为
UsernamePasswordAuthenticationToken
,然后交给AuthenticationManager
进行认证。
- 用于处理传统的基于用户名和密码的表单认证。它会从 HTTP 请求的参数中提取用户名和密码,并将其封装为
AbstractPreAuthenticatedProcessingFilter
:- 用于预认证模式(pre-authentication)。在此模式下,认证信息(如用户身份)已经包含在请求头中或其他地方。此过滤器会从请求中提取认证信息并进行认证。
OAuth2LoginAuthenticationFilter
:- 用于 OAuth 2.0 登录流程,处理 OAuth2 登录请求,拦截并解析授权码等信息,执行 OAuth2 认证。