SpringSecurity流程
SpringSecurity详细流程
Spring Security采用的是责任链的设计模式,由一组很长的过滤器链组成,我们先来看看其详细的流程图,然后详细分析每个过滤器在流程图中所处位置扮演了什么样的角色,发挥了什么样的作用。
1. SpringSecurity详细流程图:
2. SpringSecurity常用过滤器
2.1 WebAsyncManagerIntegrationFilter
Web异步管理集成过滤器。此过滤器使得WebAsync异步线程能够获取到当前认证信息。用于集成SecurityContext到Spring异步执行机制中的WebAsyncManager。用来处理异步请求的安全上下文。
WebAsyncManager是一个异步请求管理器,主要是针对异步请求如何能和同步请求一样对一些数据进行处理。 WebAsyncManagerIntegrationFilter就是用来管理异步请求中SecuurityContext的生命周期的,主要是通过SecurityContextCallableProcessingInterceptor来持有SecurityContext,然后注入到SecurityContextHolder(SecurityContextHolder是其他组件获取SecurityContext的公共类),再到最后清理SecurityContext
具体逻辑:
- 从请求属性上获取所绑定WebAsyncManager,如果尚未绑定则先做绑定
- 从asyncManager中获取key为CALLABLE_INTERCEPTOR_KEY的安全上下文多线程处理器SecurityContextCallableProcessingInterceptor,如果获取到为null,则新建一个并绑定CALLABLE_INTERCEPTOR_KEY注册到asyncManager中。
SecurityContextCallableProcessingInterceptor实现了接口CallableProcessingInterceptor,当他被应用于一次异步请求时,beforeConcurrentHandling()方法会在调用者线程执行,该方法会相应的从当前线程获取SecurityContext,然后 被调用者线程中执行逻辑时,会使用这个SecurityContext,从而实现安全上下文从调用者线程到被调用者线程的传输。
2.2 SecurityContextPersistenceFilter
SecurityContextPersistenceFilter主要有两个任务:
- 在请求到达时处理前,从SecurityContextRepository中获取安全上下文信息填充到SecurityContextHolder
- 在请求处理结束后返回响应时,将SecurityContextHolder中的安全上下文信息保存回SecurityContextRepository,并清空SecurityContextHolder。
工作流程:
对于一些跨request保持的场景,通常时通过session来保存request中的信息,当下次请求过来时,可以通过session获取之前请求中的信息。这个Filter就是处理请求最后的保存操作
-
一个安全上下文在请求1处理过程中被创建并保存到SecurityContextHolder中
-
请求1处理结束时,会将SecurityContextHolder中的安全上下文信息保存到HttpSession(SecurityContextRepository负责安全上下文的持久化)
-
后续该用户会话中的另一个请求2处理过程开始时,Filter会将安全上下文从HttpSession中恢复到SecurityContextHolder
-
请求2处理结束时,Filter会将SecurityContextHolder中的安全上下文保存到HttpSession
-
后续其他请求重复重置/恢复SecurityContext的动作
2.3 HeaderWriterFilter
往请求头或响应头中写入一些信息。比如 X-Frame-Options, X-XSS-Protection ,X-Content-Type-Options。
通过shouldWriteHeadersEagerly控制写入时机,true时写操作在过滤链执行前,否则过滤链执行完毕后再进行写入
2.4 CsrfFilter
用于处理跨站请求伪造,防止CSRF攻击。
2.5 LogoutFilter
用于处理退出登录,可配置自定义的登出逻辑。
2.6 UserNamePasswordAuthenticationFilter
用于处理基于表单的登录请求,从表单中获取用户名和密码。默认情况下处理来自“/login”的请求,从表单中获取用户名和密码时,默认使用表单name值为username和password,这个值可以通过设置这个过滤器的usernameParameter和passwordParameter两个参数进行修改。
提交的username和password会被封装为未经认证的AuthenticationToken进行一系列的认证
2.7 DefaultLoginPageGeneratingFilter
如果没有配置登录页面,那么系统初始化时就会配置这个过滤器,并且用于在需要进行登录时生成一个登录表单页面
2.8 BasicAuthenticationFilter
检测和处理http basic认证
2.9 RequestCacheAwareFilter
请求缓存过滤器,主要作用是认证完成后恢复认证前的请求继续执行
用户认证成功后,重新恢复因登录被打断的请求。当匿名访问 一个需要授权的资源时,会跳转到认证处理逻辑,此时请求被缓存。在认证逻辑处理完成后,从缓存中获取最开始的资源请求进行再次请求。
2.10 SecurityContextHolderAwareRequestFilter
主要是包装请求对象request
目的是实现servlet api的一些接口方法:isUserRole、getRemoteUser。在springSecurity中就是通过这个过滤器实现的
2.11 AnonymousAuthenticationFilter
匿名认证过滤器。对于SpringSecurity来说,所有资源的访问都是有Authentication的,对于无需登录认证即可直接访问的资源会授予匿名用户身份
检测SecurityContextHolder中是否存在Authentication对象,如果不存在则为其提供一个匿名Authentication
2.12 SessionManagementFilter
管理session的过滤器。内部维护了一个SessionAuthenticationStrategy用于管理session
2.13 ExceptionTranslationFilter
处理AccessDecisionException和AuthenticationException异常。
2.14 FilterSecurityInterceptor
请求鉴权过滤器,这个过滤器决定了访问特定路径应该具备的权限,访问的用户的角色,权限是什么,访问的路径需要什么样的角色和权限。这些判断和处理都由该过滤器完成
2.15 RemembeMeAuthenticationFilter
处理“记住我”功能的过滤器。当用户没有登录而直接访问资源时,从cookie里找出用户的信息,如果springsecurity能够识别用户提供的remember me cookie,用户将不必填写用户名和密码,而是直接登录进入系统,该过滤器默认不开启
Spring Security核心流程总结
一系列的过滤器处理逻辑仍旧十分复杂,有一些时默认开启,有一些则需要进行相应的配置才会生效,专注于重点功能逻辑,梳理一下Spring Security的访问流程:
是否是登出->是否是登录->权限校验
-
用户发起请求,进入过滤器链后,到达LogoutFilter时,会先判断是否时登出请求
- 登出请求: 则通过LogoutHandler处理登出逻辑
- 登出成功: 进入LogoutSuccessHandler执行登出成功后的处理
- 登出失败: 进入LogoutFailureHandler执行登出失败后的处理
- 不是登出请求: 则检查是否配置了登录页,若没有配置则会通过DefaultLoginPageGeneratingFilter生成默认的登录页
- 登出请求: 则通过LogoutHandler处理登出逻辑
-
判断是否为登录请求,
- 是登录请求: 进入UserNamePasswordAuthenticationFilter过滤器,进行Authentication认证处理
- 不是登录请求: 则进入下一个过滤器。
-
到达FilterSecurityInterceptor,鉴权过滤器,进行权限校验处理,判断当前用户是否拥有当前请求路径的访问权限
- 拥有访问权限:进入controller执行代码逻辑
- 无访问权限: 进入AccessDeniedHandler执行鉴权失败逻辑。
转载自:https://juejin.cn/post/7242198986261266493