04 SecurityContextHolder与SecurityContext说明
该篇记录一下SecurityContextHolder与SecurityContext两个类,当然还有与它们关系密码的SecurityContextPersistenceFilter.java这个过滤器
1. SecurityContext.java
查看spring security的源码,发现它就是个接口,spring security提供了一个默认的实现SecurityContextImpl.java. 仔细一看,该类其实就是对Authentication对象进行了封装,当然,覆写了equals和hashCode两个方法。
public class SecurityContextImpl implements SecurityContext {
private static final long serialVersionUID = SpringSecurityCoreVersion.SERIAL_VERSION_UID;
// ~ Instance fields
// ================================================================================================
private Authentication authentication;
public SecurityContextImpl() {}
public SecurityContextImpl(Authentication authentication) {
this.authentication = authentication;
}
// ~ Methods
// ========================================================================================================
@Override
public boolean equals(Object obj) {
if (obj instanceof SecurityContextImpl) {
SecurityContextImpl test = (SecurityContextImpl) obj;
if ((this.getAuthentication() == null) && (test.getAuthentication() == null)) {
return true;
}
if ((this.getAuthentication() != null) && (test.getAuthentication() != null)
&& this.getAuthentication().equals(test.getAuthentication())) {
return true;
}
}
return false;
}
@Override
public Authentication getAuthentication() {
return authentication;
}
@Override
public int hashCode() {
if (this.authentication == null) {
return -1;
}
else {
return this.authentication.hashCode();
}
}
@Override
public void setAuthentication(Authentication authentication) {
this.authentication = authentication;
}
}
2. SecurityContextHolder.java
官方解释就是: Associates a given {@link SecurityContext} with the current execution thread.(与当前线程的securitycontext有关)
其实,它就是存储SecurityContext对象。
默认的策略采用ThreadLocal
源代码如下:
public class SecurityContextHolder {
// ~ Static fields/initializers
// =====================================================================================
public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";
public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";
public static final String MODE_GLOBAL = "MODE_GLOBAL";
public static final String SYSTEM_PROPERTY = "spring.security.strategy";
private static String strategyName = System.getProperty(SYSTEM_PROPERTY);
private static SecurityContextHolderStrategy strategy;
private static int initializeCount = 0;
static {
initialize();
}
private static void initialize() {
// 如果没有设置自定义的策略,就采用MODE_THREADLOCAL模式
if (!StringUtils.hasText(strategyName)) {
// Set default
strategyName = MODE_THREADLOCAL;
}
// ThreadLocal策略
if (strategyName.equals(MODE_THREADLOCAL)) {
strategy = new ThreadLocalSecurityContextHolderStrategy();
}
// 采用InheritableThreadLocal,它是ThreadLocal的一个子类
else if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {
strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
}
// 全局策略,实现方式就是static SecurityContext contextHolder
else if (strategyName.equals(MODE_GLOBAL)) {
strategy = new GlobalSecurityContextHolderStrategy();
}
else {
// 自定义的策略,通过返回创建出
try {
Class<?> clazz = Class.forName(strategyName);
Constructor<?> customStrategy = clazz.getConstructor();
strategy = (SecurityContextHolderStrategy) customStrategy.newInstance();
}
catch (Exception ex) {
ReflectionUtils.handleReflectionException(ex);
}
}
initializeCount++;
}
}
补充说明: InheritableThreadLocal 与 ThreadLocal的区别
ThreadLocal , 存储变量只能被当前线程使用
InheritableThreadLocal , 父线程中存储的变量子线程也可使用
3. SecurityContextPersistenceFilter.java
该过滤器是spring security 过滤器链的第一个过滤器,所以请求进来时,第一个经过它,响应数据时,最后一个经过它。
请求进来时, 它会检测session中是否有SecurityContext,如果有,它会将SecurityContext从session中拿出来,放到线程中。
当请求响应时,它会检测线程是否有SecurityContext,如果有,它会将SecurityContext放到session中去。
这样,不同的请求,就可以拿到同一个认证信息 Authentication
下面看具体源码:
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res; ...... // 将request与response对象封装成一个HttpRequestResponseHolder对象,减少方法列表个数
HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request,response); // 检测session中是否有SecurityContext,如果有就从session中获取,如果没有,创建一个新的
SecurityContext contextBeforeChainExecution = repo.loadContext(holder); try {
// 将SecurityContext对象放到当前执行的线程中
SecurityContextHolder.setContext(contextBeforeChainExecution);
// 调用过滤器链
chain.doFilter(holder.getRequest(), holder.getResponse()); }
finally {
// 从当前线程中获取SecurityContext对象
SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
// 清空当前线程中的SecurityContext
SecurityContextHolder.clearContext();
// 将SecurityContext放入到session中
repo.saveContext(contextAfterChainExecution, holder.getRequest(),holder.getResponse());
}
}
接着看下loadContext(holder)方法的源码
public SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder) {
HttpServletRequest request = requestResponseHolder.getRequest();
HttpServletResponse response = requestResponseHolder.getResponse();
// 获取session
HttpSession httpSession = request.getSession(false);
// 从session中获取SecurityContext对象
SecurityContext context = readSecurityContextFromSession(httpSession);
// 如果是null,就创建一个新的
if (context == null) {
context = generateNewContext();
}
.......
return context;
}
4. 总结
这几个相关的类看完了,感叹spring的代码就是写得好!
(1) SecurityContextHolder它的责任就是存储SecurityContext对象,但是怎么存储,采用何种存储策略则是通过SecurityContextHolderStrategy来实现的。SecurityContextHolderStrategy只是一个抽象接口,spring security 默认提供了几种存储策略,它们都实现了SecurityContextHolderStrategy接口。如果我们想自定义存储策略,肯定也得实现SecurityContextHolderStrategy。这样子,SecurityContextHolder 只需要提供存储策略的方式,至于如何实现这种存储策略,则完全交给了SecurityContextHolderStrategy及其实现类来控制,做到责任分离吧!
(2) SecurityContextPersistenceFilter也是骚了一逼,将交量转换用得神了!
04 SecurityContextHolder与SecurityContext说明的更多相关文章
- 核心组件之SecurityContextHolder
作用:保留系统当前的安全上下文细节,其中就包括当前使用系统的用户的信息. 上下文细节怎么表示? 用SecurityContext对象来表示 每个用户都会有它的上下文,那这个Securi ...
- spring security源码分析之web包分析
Spring 是一个非常流行和成功的 Java 应用开发框架.Spring Security 基于 Spring 框架,提供了一套 Web 应用安全性的完整解决方案.一般来说,Web 应用的安全性包括 ...
- Spring Security(09)——Filter
目录 1.1 Filter顺序 1.2 添加Filter到FilterChain 1.3 DelegatingFilterProxy 1.4 FilterChainPr ...
- Spring Security 入门(1-6-2)Spring Security - 内置的filter顺序、自定义filter、http元素和对应的filterChain
Spring Security 的底层是通过一系列的 Filter 来管理的,每个 Filter 都有其自身的功能,而且各个 Filter 在功能上还有关联关系,所以它们的顺序也是非常重要的. 1.S ...
- Spring Security 架构与源码分析
Spring Security 主要实现了Authentication(认证,解决who are you? ) 和 Access Control(访问控制,也就是what are you allowe ...
- Spring Security 过滤器链
Alias Filter Class Namespace Element or Attribute CHANNEL_FILTER ChannelProcessingFilter http/interc ...
- Spring Security 5.0.x 参考手册 【翻译自官方GIT-2018.06.12】
源码请移步至:https://github.com/aquariuspj/spring-security/tree/translator/docs/manual/src/docs/asciidoc 版 ...
- 如何使用Spring Security手动验证用户
1.概述 在这篇快速文章中,我们将重点介绍如何以编程方式在Spring Security和Spring MVC中设置经过身份验证的用户. 2. Spring Security 简而言之,Spring ...
- Spring Security 梳理 - DelegatingFilterProxy
可能你会觉得奇怪,我们在web应用中使用Spring Security时只在web.xml文件中定义了如下这样一个Filter,为什么你会说是一系列的Filter呢? <filter> ...
随机推荐
- Jmeter 上传下载文件
最近很多同学都在问jmeter上传.下载文件的脚本怎么做,要压测上传.下载文件的功能,脚本怎么做,网上查了都说的很含糊,这次呢,咱们就好好的把jmeter的上传下载文件好好缕缕,都整明白了,怎么个过程 ...
- 【CDN+】 Hive 入门 以及Handoop 系统认知
前言 本文主要介绍Hive 的基础概念,以及Handoop的大体架构,组件依赖,对于大数据有个总体的认识 Hive 基础概念 官网:https://hive.apache.org/ The Apach ...
- Jmeter 循环控制器 遍历结果
1.测试计划,添加Mysql jar包 2.线程组 3.JDBC Connection Configuration,配置Mysql 4.添加JDBC Request,将查询出的数据对应的存入usern ...
- vue-wacth监听事件
2019-08-05 0:20 Vue.js 监听属性 watch,我们可以通过 watch 来响应数据的变化. 以下实例通过使用 watch 实现计数器:(此时我就想了一下,好像绑定点击事件,也 ...
- vue-安装及新建一个项目
1.首先我们需要安装node.js,下载地址是:https://nodejs.org/en/ 之后是node.js的正常安装步骤: 接着打开window+R输入cmd回车进入命令行模块 2.确认nod ...
- Colourful Rectangle【扫描线】
题目链接 很明显的可以发现是一个扫描线的问题,但是怎么处理区域呢,发现只有三种颜色,也就是最多也就是7种状态,那么我们可以进行一个状态压缩即可. 但是,在向上pushup的时候,存在我们要以子树的状态 ...
- jQuery easyUI 使用 datagrid 表格
获取后台数据依旧是使用一般处理程序(ashx) ,分页上添加一个函数(pagerFilter(data)) 前端代码: <%@ Page Language="C#" Auto ...
- Windows程序设计--(三)窗口与消息
3.1 窗口的创建 3.1.1 系统结构概述 所谓「Windows给程序发送消息」,是指Windows呼叫程序中的一个函数,该函数的参数描述了这个特定消息.这种位于Windows程序中的函数称为「窗口 ...
- springcloud费话之配置中心server修改
目录: springcloud费话之Eureka基础 springcloud费话之Eureka集群 springcloud费话之Eureka服务访问(restTemplate) springcloud ...
- Vue PC端图片预览插件
*手上的项目刚刚搞完了,记录一下项目中遇到的问题,留做笔记: 需求: 在项目中,需要展示用户上传的一些图片,我从后台接口拿到图片url后放在页面上展示,因为被图片我设置了宽度限制(150px),所以图 ...