【Spring Security】3. 认证流程分析

本文深入解析了Spring Security的架构和过滤器链,包括DelegatingFilterProxy、FilterChainProxy和SecurityFilterChain的角色。重点介绍了AbstractAuthenticationProcessingFilter和UsernamePasswordAuthenticationFilter在表单认证中的作用,以及AuthenticationManager和ProviderManager的认证逻辑。当请求到达Spring Security时,经过一系列过滤器处理,最终通过UsernamePasswordAuthenticationFilter进行身份验证,利用AuthenticationManager进行认证,成功后将Authentication存入SecurityContext,并处理RememberMe和AuthenticationSuccessHandler等后续操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1. Spring Security大局观

以下内容基于Servlet应用进行分析。首先通过官方的Spring Security在基于Servlet应用的架构图,了解下请求是如何到达Spring Security的。
SecurityFilterChain
Spring在Filter Chain中加入DelegatingFilterProxy过滤器;DelegatingFilterProxy将所有请求委托给FilterChainProxyFilterChainProxy根据请求调用合适的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来完成身份认证。

UsernamePasswordAuthenticationFilterAbstractAuthenticationProcessingFilter的实现类,用于处理基于表单提交的认证请求,默认匹配/login请求。

UsernamePasswordAuthenticationFilterattemptAuthentication方法的实现: 从HttpServletRequest中提取出username和password,并根据username和password创建UsernamePasswordAuthenticationToken实例,最后调用AuthenticationManagerauthenticate方法进行认证。

UsernamePasswordAuthenticationTokenAuthentication的一种实现,用于简单表示用户名和密码的请求令牌。


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> providersAuthenticationManager parent

AuthenticationProvider用于针对不同Authentication进行具体的认证。例如DaoAuthenticationProvider针对UsernamePasswordAuthenticationToken进行认证。

为了文章篇幅简洁,这里简述下ProviderManager的处理逻辑,不进行代码展示:

  1. 首先通过循环providers进行身份认证,直到得到非空响应(非空响应表示认证成功);
  2. providers前面的AuthenticationProvider出现了除AccountStatusExceptionInternalAuthenticationServiceException之外的异常,会使用lastException变量记录异常,然后遍历下一个AuthenticationProvider进行认证;如果后续的AuthenticationProvider认证成功,则忽略前面的异常。
  3. 如果providers中的AuthenticationProvider都认证失败,且指定了parent,则使用parent进行认证。

3. 认证过程

  1. 在Spring Security中,当前请求到达DelegatingFilterProxy时,DelegatingFilterProxy会调用FilterChainProxydoFilter方法来处理请求;
  2. FilterChainProxy先从filterChains集合中获取匹配请求的SecurityFilterChain,接着调用SecurityFilterChaingetFilters方法获得Filter集合;最后以Filter Chain方式执行Filter集合;
  3. 当执行到UsernamePasswordAuthenticationFilter,且是/login请求时,则开始尝试进行认证处理。先从HttpServletRequest中提取username和password,并根据username和password构建UsernamePasswordAuthenticationToken
  4. 接着将UsernamePasswordAuthenticationToken作为AuthenticationManagerauthenticate方法的参数,UsernamePasswordAuthenticationFilter默认使用ProviderManager实例;
  5. ProviderManager首先通过循环providers集合进行身份认证,如果providers集合都认证失败,就尝试交给parent进行认证;如果认证成功,则返回一个新的Authentication
  6. 如果认证成功,UsernamePasswordAuthenticationFilter将新的Authentication存放到当前当前线程的SecurityContext中;发布InteractiveAuthenticationSuccessEvent事件;进行RememberMe处理;调用AuthenticationSuccessHandler
  7. 如果认证失败,如果身份验证失败,它将委托给配置的AuthenticationFailureHandler以允许将失败信息传达给客户端。 默认实现是SimpleUrlAuthenticationFailureHandler,它向客户端发送 401 错误代码。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值