SpringSecurity之SecurityContextHolder使用解读

 更新时间:2023年03月17日 14:08:18   作者:chihaihai  
这篇文章主要介绍了SpringSecurity之SecurityContextHolder使用解读,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

Java技术迷

之前在使用SpringSecurity的过程中并没有把很多东西理解透彻,找了很多学习资料也都只是是很浅显了告诉你怎么使用这个东西。现在只能自己回过头来研究研究。。。。终究是一个人扛下了所有/(ㄒoㄒ)/~~。

GO,现在越看spring源码越觉得里面注释是真的详细,虽然英语很菜耐不住有翻译哈哈哈。

介绍

看了几篇大佬的技术博客里面都介绍到,SecurityContextHolder是保存全上下文对象(SecurityContext)的地方。对于这种说法我感觉是完全不正确的,如果后面有新的认知我会回来进行修改。

我认为SecurityContextHolder只是为SecurityContext提供一种存储策略,只是主导了他的存储方式及地址。

使用中我们表面上看起来SecurityContext的存储都是通过SecurityContextHolder在控制人们就习以为常的说成了Security Context存储在了SecurityContextHolder中,至于真相我们看源码慢慢分析。

1
2
3
4
5
6
7
8
9
10
11
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;

首先从源码可以看到SecurityContextHolder提供了一个SecurityContextHolderStrategy存储策略进行上下文的存储,进入到Security ContextHolderStrategy接口,由下图我们可以清晰的看到其总共有三个实现类。

分别对应三种存储策略,这里我不知道为什么99的文章都只说了threadlocal和global两种。

要不是看了下实现类我都信了。

在这里插入图片描述

就跟字面意思一样三种策略分别对应threadlocal,global,InheritableThreadLocal三种方式。

继续回到源码我们详细看这三种方式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
private static void initialize() {
    if (!StringUtils.hasText(strategyName)) {
        // 如果没有设置自定义的策略,就采用MODE_THREADLOCAL模式
        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 to load a custom strategy  自定义的策略,通过返回创建出
        try {
            Class<?> clazz = Class.forName(strategyName);
            Constructor<?> customStrategy = clazz.getConstructor();
            strategy = (SecurityContextHolderStrategy) customStrategy.newInstance();
        }
        catch (Exception ex) {
            ReflectionUtils.handleReflectionException(ex);
        }
    }
 
    initializeCount++;
}

由源码我们可以得出SecurityContextHolder 默认使用的是THREADLOCAL模式,光从名字看感觉就是存储在threadlocal中的策略到底是不是我们去源码中分别一探究竟:

ThreadLocalSecurityContextHolderStrategy

1
2
3
4
5
6
7
8
final class ThreadLocalSecurityContextHolderStrategy implements
        SecurityContextHolderStrategy {
    // ~ Static fields/initializers
    // =====================================================================================
 
    private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<>();
    。。。。。。
}

InheritableThreadLocalSecurityContextHolderStrategy

1
2
3
4
5
6
7
8
final class InheritableThreadLocalSecurityContextHolderStrategy implements
        SecurityContextHolderStrategy {
    // ~ Static fields/initializers
    // =====================================================================================
 
    private static final ThreadLocal<SecurityContext> contextHolder = new InheritableThreadLocal<>();
    。。。。。。
}

GlobalSecurityContextHolderStrategy

1
2
3
4
5
6
7
final class GlobalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
    // ~ Static fields/initializers
    // =====================================================================================
 
    private static SecurityContext contextHolder;
    。。。。。。
}

到这里那些说SecurityContext存储在SecurityContextHolder的大佬们我认为应该是不严谨的。

默认是将SecurityContext存储在threadlocal中,可能是spring考虑到目前大多数为BS应用,一个应用同时可能有多个使用者,每个使用者又对应不同的安全上下,Security Context Holder为了保存这些安全上下文。

缺省情况下,使用了ThreadLocal机制来保存每个使用者的安全上下文。

因为缺省情况下根据Servlet规范,一个Servlet request的处理不管经历了多少个Filter,自始至终都由同一个线程来完成。这样就很好的保证了其安全性。

但是当我们开发的是一个CS本地应用的时候,这种模式就不太适用了。

spring早早的就考虑到了这种情况,这个时候我们就可以设置为Global模式仅使用一个变量来存储SecurityContext。比如还有其他的一些应用会有自己的线程创建,并且希望这些新建线程也能使用创建者的安全上下文。

这种效果,我们就可以通过将SecurityContextHolder配置成MODE_INHERITABLETHREADLOCAL策略达到。

SecurityContext又到底是个什么东西呢?稍后新开一遍学习记录。

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

蓄力AI

微信公众号搜索 “ 脚本之家 ” ,选择关注

程序猿的那些事、送书等活动等着你

原文链接:https://blog.csdn.net/chihaihai/article/details/104830066

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若内容造成侵权/违法违规/事实不符,请将相关资料发送至 reterry123@163.com 进行投诉反馈,一经查实,立即处理!

相关文章

  • Springboot实现VNC的反向代理功能

    Springboot实现VNC的反向代理功能

    这篇文章主要介绍了Springboot实现VNC的反向代理,搭建过程也很简单,通过注册bean拦截指定URL路径进行自定义操作,具体实例代码跟随小编一起看看需要的朋友可以参考下
    2021-09-09
  • 美化java代码,从合理注释开始

    美化java代码,从合理注释开始

    在Java的编写过程中我们需要对一些程序进行注释,除了自己方便阅读,更为别人更好理解自己的程序,可以是编程思路或者是程序的作用,总而言之就是方便自己他人更好的阅读。下面我们来一起学习一下吧
    2019-06-06
  • 如何从官网下载Hibernate jar包的方法示例

    如何从官网下载Hibernate jar包的方法示例

    这篇文章主要介绍了如何从官网下载Hibernate jar包的方法示例,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2019-04-04
  • IDEA调试技巧条件断点实现步骤详解

    IDEA调试技巧条件断点实现步骤详解

    这篇文章主要介绍了IDEA调试技巧条件断点实现步骤详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-09-09
  • Java编程实现基于TCP协议的Socket聊天室示例

    Java编程实现基于TCP协议的Socket聊天室示例

    这篇文章主要介绍了Java编程实现基于TCP协议的Socket聊天室,结合实例形式详细分析了java基于TCP协议的Socket聊天室客户端与服务器端相关实现与使用技巧,需要的朋友可以参考下
    2018-01-01
  • Java线程Timer定时器用法详细总结

    Java线程Timer定时器用法详细总结

    在本篇文章里小编给大家整理的是关于Java线程Timer定时器用法详细总结内容,需要的朋友们学习下吧。
    2020-02-02
  • Windows下Java调用可执行文件代码实例

    Windows下Java调用可执行文件代码实例

    这篇文章主要介绍了Windows下Java调用可执行文件代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-12-12
  • SpringBoot 整合 Netty 多端口监听的操作方法

    SpringBoot 整合 Netty 多端口监听的操作方法

    Netty提供异步的、基于事件驱动的网络应用程序框架,用以快速开发高性能、高可靠性的网络 IO 程序,是目前最流行的 NIO 框架,这篇文章主要介绍了SpringBoot 整和 Netty 并监听多端口,需要的朋友可以参考下
    2023-10-10
  • SpringBoot统计接口调用耗时的三种方式

    SpringBoot统计接口调用耗时的三种方式

    在实际开发中,了解项目中接口的响应时间是必不可少的事情,SpringBoot 项目支持监听接口的功能也不止一个,接下来我们分别以 AOP、ApplicationListener、Tomcat 三个方面去实现三种不同的监听接口响应时间的操作,需要的朋友可以参考下
    2024-06-06
  • Spring和SpringMVC父子容器关系初窥(小结)

    Spring和SpringMVC父子容器关系初窥(小结)

    这篇文章主要介绍了Spring和SpringMVC父子容器关系初窥(小结),小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-01-01

最新评论