总文档 :文章目录
Github : github.com/black-ant
一 . 前言
上一篇讲了 Security 的 Filter 是怎么运行的 , 这一篇我们来看看 Security 的认证流程 .
二 . 认证信息的流转
2.1 SecurityContext 基本对象信息
Security 核心信息就是 SecurityContext , 我们来看看认证信息是怎么确定和流转的
SecurityContextHolder 是 Spring Security 存储被验证者的详细信息的地方。Spring Security 不关心 SecurityContextHolder 是如何填充的。如果它包含一个值,则将其用作当前经过身份验证的用户。
生成一个 SecurityContext
1 | java复制代码// 表明用户已通过身份验证的最简单方法是直接设置 SecurityContextHolder |
获得已经认证的用户
1 | java复制代码// Step 1 : 获取 SecurityContext |
SecurityContextHolder 的相关逻辑
- 默认情况下 SecurityContextHolder 使用 ThreadLocal 来存储这些细节 (PS : 也可以通过 SecurityContextHolder.MODE global 配置)
- 第一个是设置系统属性
- 第二个是调用 SecurityContextHolder 上的静态方法
- Spring Security 的 FilterChainProxy 确保 SecurityContext 总是被清除
1 | java复制代码// SecurityContextHolder 提供了以下的参数 |
GlobalSecurityContextHolderStrategy : 其中 SecurityContext 就是个静态变量
InheritableThreadLocalSecurityContextHolderStrategy : 其中包含一个 ThreadLocal<SecurityContext>
ThreadLocalSecurityContextHolderStrategy : 和上一个没什么区别
2.2 SecurityContext 流程
FilterChainProxyAbstractAuthenticationProcessingFilterDatabaseAuthenticationFilterAuthenticationManagerProvider这里会调用相关Handler 最终处理 Authentication调用 doFilter调用attemptAuthentication通过 Manager 调用 provider调用 Provider 请求 Authentication然会 Authentication返回 Authentication返回 AuthenticationFilterChainProxyAbstractAuthenticationProcessingFilterDatabaseAuthenticationFilterAuthenticationManagerProvider
Step 1 : 调用 Provider 处理情况 , 这里认证完成后返回了一个 Authentication
1 | java复制代码// 回忆一下 , 之前 Filter 中 , 调用 AuthenticationManager 开始了 Provider 的流程 |
Step 2 : Provider 处理
这里的 AuthenticationManager 主要是 ProviderManager 主要是这些 ,我们仅保留其中比较重要的逻辑 :
1 | java复制代码public Authentication authenticate(Authentication authentication) |
可以看到 ,到这一步 Provider 返回了一个 Authentication 回去
Step 3 : AbstractAuthenticationProcessingFilter 处理
从第二步 Prodiver 返回了 Authentication , 他最终被传递到 AbstractAuthenticationProcessingFilter 中
1 | java复制代码// AbstractAuthenticationProcessingFilter 伪代码 : |
至此 , Provider 产生的 Authentication 成功放入 容器中
扩展 SavedRequestAwareAuthenticationSuccessHandler 处理 Success 结果
总结一下就是定制缓存和跳转关系 >>>
1 | java复制代码C- SavedRequestAwareAuthenticationSuccessHandler |
以上是认证从和认证失败的流程图 , 可以看到具体的处理类 :
总结一下认证成功和认证失败分别干了什么 :
如果认证失败:
- Security contextholder 被清空了。
- 调用 RememberMeServices.loginFail。如果没有配置 rememberme,这是一个 no-op
- 调用 AuthenticationFailureHandler。
同时对比一下认证成功:
- 会在新登录时通知 SessionAuthenticationStrategy
- 在 SecurityContextHolder 上设置身份验证,然后 SecurityContextPersistenceFilter 将 SecurityContext 保存到 HttpSession 中
- 调用 RememberMeServices.loginSuccess。如果没有配置 remember me,这是一个 no-op
- ApplicationEventPublisher 发布交互式身份验证连接
- 调用 AuthenticationSuccessHandler
三 . 再次访问和退出
上面说了一个认证过程中发生了什么 , 这里我们看下认证完成后再次访问>>>
3.1 认证后访问
1 | java复制代码// 前面说了 , 认证完成后会写入 SecurityContextHolder , Security 通过判断 SecurityContext 来校验用户 |
PS : 因为是基于 Session 管理 , 所以过一会就过期了
当然这是基于 Session 的模式 ,生命周期和 Session 等同 ,但是通常会常用更长的生命周期方案 ,比如 AccessToken , Cookie 等等 ,而 Session 只是为了维持一个认证的临时状态
3.2 Logout 退出
Logout 相关类 :
- PersistentTokenBasedRememberMeServices
- TokenBasedRememberMeServices
- CookieClearingLogoutHandler
- CsrfLogoutHandler
- SecurityContextLogoutHandler
- HeaderWriterLogoutHandler
同样的 , Logout 也有 Filter 和 Handler
- LogoutFilter
- SimpleUrlLogoutSuccessHandler
- HttpStatusReturningLogoutSuccessHandler
和前面分析 Filter 一样 , 其核心还是通过 LogoutFilter 来进行 :
1 | java复制代码this.handler.logout(request, response, auth); |
总结 :
至此 , 一个完整的 Security 生命周期就看完了, 其实很简单 , 总结起来就是 :
- Filter 做业务决定
- AuthenticationManager 决定校验方式
- Provider 进行认证校验
- Handler做结果处理已经外部跳转
后面一章我们来详细看看Security 的配置逻辑 ,看看底层发生了什么
本文转载自: 掘金