SpringSecurity基本原理 认证流程源码剖析

SpringSecurity基本原理

一、基本认证流程

SpringSecurity基本原理 认证流程源码剖析_第1张图片

SpringSecurity 本质是一个过滤器链:

从启动是可以获取到过滤器链:

org.springframework.security.web.下的:
context.request.async.WebAsyncManagerIntegrationFilter
context.SecurityContextPersistenceFilter 
header.HeaderWriterFilter
csrf.CsrfFilter
authentication.logout.LogoutFilter 
authentication.UsernamePasswordAuthenticationFilter 
authentication.ui.DefaultLoginPageGeneratingFilter 
authentication.ui.DefaultLogoutPageGeneratingFilter
savedrequest.RequestCacheAwareFilter
servletapi.SecurityContextHolderAwareRequestFilter
authentication.AnonymousAuthenticationFilter 
session.SessionManagementFilter 
access.ExceptionTranslationFilter 
access.intercept.FilterSecurityInterceptor

二、三个重要的过滤器

代码底层流程,重点看三个过滤器:

(1)、FilterSecurityInterceptor

是一个方法级的权限过滤器, 基本位于过滤链的最底部。(基本使用基本用不到)该过滤器是过滤器链的最后一个过滤器,根据资源权限配置来判断当前请求是否有权限访问对应的资源。如果访问受限会抛出相关异常,并由 ExceptionTranslationFilter 过滤器进行捕获和处理。

SpringSecurity基本原理 认证流程源码剖析_第2张图片

super.beforeInvocation(fi) 表示查看之前的 filter 是否通过。
fi.getChain().doFilter(fi.getRequest(), fi.getResponse());表示真正的调用后台的服务(放行)。

(2)、ExceptionTranslationFilter

是个异常过滤器,用来处理在认证授权过程中抛出的异常。该过滤器不需要我们配置,对于前端提交的请求会直接放行,捕获后续抛出的异常并进行处理(例如:权限访问限制)。

(3)、UsernamePasswordAuthenticationFilter

对前端提交的/login 的 POST 请求做拦截,校验表单中用户名,密码(身份认证)。

UsernamePasswordAuthenticationFilter 过滤器的 doFilter() 方法实现在其抽象父类AbstractAuthenticationProcessingFilter 中:

SpringSecurity基本原理 认证流程源码剖析_第3张图片
SpringSecurity基本原理 认证流程源码剖析_第4张图片

三、分析UsernamePasswordAuthenticationFilter 类

说回 UsernamePasswordAuthenticationFilter 类:

SpringSecurity基本原理 认证流程源码剖析_第5张图片

(1)、创建 UsernamePasswordAuthenticationToken 对象

上述过程创建的 UsernamePasswordAuthenticationToken 对象是 Authentication 接口的实现类,该类有两个构造器,一个用于封装前端请求传入的未认证的用户信息,一个用于封装认证成功后的用户信息:
public class UsernamePasswordAuthenticationToken extends AbstractAuthenticationToken {
SpringSecurity基本原理 认证流程源码剖析_第6张图片

而AbstractAuthenticationToken 实现了 Authentication 接口

SpringSecurity基本原理 认证流程源码剖析_第7张图片

(2)、ProviderManager 进行认证方式类型的判断

上述过程中,UsernamePasswordAuthenticationFilter 过滤器的 attemptAuthentication() 方法将未认证的 Authentication 对象传入ProviderManager 类的 authenticate() 方法进行身份认证。ProviderManager 是 AuthenticationManager 接口的实现类,该接口是认证相关的核心接口,也是认证的入口。在实际开发中,我们可能有多种不同的认证方式,例如:用户名+ 密码、邮箱+密码、手机号+验证码等,而这些认证方式的入口始终只有一个,那就是 AuthenticationManager。在该接口的常用实现类 ProviderManager 内部会维护一个 List 列表,存放多种认证方式,实际上这是委托者模式 (Delegate)的应用。每种认证方式对应着一个 AuthenticationProvider, AuthenticationManager 根据认证方式的不同(根据传入的 Authentication 类型判断委托对应的 AuthenticationProvider 进行用户认证。
SpringSecurity基本原理 认证流程源码剖析_第8张图片
SpringSecurity基本原理 认证流程源码剖析_第9张图片
SpringSecurity基本原理 认证流程源码剖析_第10张图片

(3)、eraseCredentials()方法去除敏感信息

上述认证成功之后过程,调用CredentialsContainer接口定义的eraseCredentials()方法去除敏感信息。查看UsernamePasswordAuthenticationToken 实现的 eraseCredentials() 方法,该方法实现在其父类public abstract class AbstractAuthenticationToken implements Authentication 中:

SpringSecurity基本原理 认证流程源码剖析_第11张图片

(4)、认证成功/失败的调用方法

上述过程就是认证流程的最核心部分,接下来重新回到UsernamePasswordAuthenticationFilter 过滤器的 doFilter() 方法,查看认证成功/失败的处理:(源码在 AbstractPreAuthenticatedProcessingFilter 类中)

SpringSecurity基本原理 认证流程源码剖析_第12张图片
SpringSecurity基本原理 认证流程源码剖析_第13张图片

权限认证总体流程:

SpringSecurity基本原理 认证流程源码剖析_第14张图片

四、权限访问流程

上一个部分通过源码的方式介绍了认证流程,下面介绍权限访问流程,主要是对ExceptionTranslationFilter 过滤器和 FilterSecurityInterceptor 过滤器进行介绍。 该过滤器是用于处理异常的,不需要我们配置,对于前端提交的请求会直接放行,捕获后 续抛出的异常并进行处理(例如:权限访问限制)。具体源码如下:

SpringSecurity基本原理 认证流程源码剖析_第15张图片

FilterSecurityInterceptor 是过滤器链的最后一个过滤器,该过滤器是过滤器链的最后一个过滤器,根据资源权限配置来判断当前请求是否有权限访问对应的资源。如果访问受限会抛出相关异常,最终所抛出的异常会由前一个过滤器 ExceptionTranslationFilter 进行捕获和处理。具体源码如下:

SpringSecurity基本原理 认证流程源码剖析_第16张图片
SpringSecurity基本原理 认证流程源码剖析_第17张图片

需要注意,Spring Security 的过滤器链是配置在 SpringMVC 的核心组件DispatcherServlet 运行之前。也就是说,请求通过 Spring Security 的所有过滤器,不意味着能够正常访问资源,该请求还需要通过 SpringMVC 的拦截器链。

五、请求间共享认证信息

(1)认证成功后封装SecurityContext对象

一般认证成功后的用户信息是通过 Session 在多个请求之间共享,那么 SpringSecurity 中是如何实现将已认证的用户信息对象 Authentication 与 Session 绑定的呢?
具体分析如下:

SpringSecurity基本原理 认证流程源码剖析_第18张图片

在前面讲解认证成功的处理方法 successfulAuthentication() 时,有以下代码:

SpringSecurity基本原理 认证流程源码剖析_第19张图片

查看 SecurityContext 接口及其实现类 SecurityContextImpl , 该类其实就是对Authentication 的封装:

查看 SecurityContextHolder 类 , 该类其实是对 ThreadLocal 的封装 , 存储 SecurityContext 对象:

SpringSecurity基本原理 认证流程源码剖析_第20张图片

SpringSecurity基本原理 认证流程源码剖析_第21张图片
SpringSecurity基本原理 认证流程源码剖析_第22张图片
在这里插入图片描述

(2)SecurityContextPersistenceFilter 过滤器

前面提到过,在 UsernamePasswordAuthenticationFilter 过滤器 认证成功之后,会在认证成功的处理方法中将已认证的用户信息对象 Authentication 封装进SecurityContext,并存入SecurityContextHolder。

之后,响应会通过 SecurityContextPersistenceFilter 过滤器,该过滤器的位置在所有过滤器的最前面,请求到来先进它,响应返回最后一个通过它,所以在该过滤器中处理已认证的用户信息对象 Authentication 与 Session 绑定。

认证成功的响应通过 SecurityContextPersistenceFilter 过滤器时,会从SecurityContextHolder 中取出封装了已认证用户信息对象 Authentication 的SecurityContext,放进 Session 中。当请求再次到来时,请求首先经过该过滤器,该过滤器会判断当前请求的 Session 是否存有SecurityContext 对象,如果有则将该对象取出再次放入 SecurityContextHolder 中,之后该请求所在的线程获得认证用户信息,后续的资源访问不需要进行身份认证;当响应再次返回时,该过滤器同样从 SecurityContextHolder 取出SecurityContext 对象,放入 Session 中。具体源码如下:

SpringSecurity基本原理 认证流程源码剖析_第23张图片

你可能感兴趣的:(Spring,spring,java,1024程序员节)