• SpringSecurity - SecurityContextHolder 源码分析


    概述

    SecurityContextHolder 可以拆分为两个单词 SecurityContextHolderHolder 意思是 持有 的意思,所以 SecurityContextHolder 的大概意思就是这个类中存放了 SecurityContext。也就是说我们首先要知道 SecurityContext 是什么

    SecurityContext

    /**
     * Interface defining the minimum security information associated with the current thread
     * of execution.
     *
     * 

    * The security context is stored in a {@link SecurityContextHolder}. *

    */
    public interface SecurityContext extends Serializable { Authentication getAuthentication(); void setAuthentication(Authentication authentication); }
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    这个接口只有一个实现类 SecurityContextImpl,里面没什么内容,这里就不粘源码了。

    从源码注释中我们知道,SecurityContext 是一个接口,这个接口定义了与当前执行的线程所关联的最小安全信息,接口定义了两个方法,setget,针对 Authentication

    public interface Authentication extends Principal, Serializable {
    
    	// 授权信息
    	Collection<? extends GrantedAuthority> getAuthorities();
    
    	Object getCredentials();
    
    	Object getDetails();
    
    	// 认证主体
    	Object getPrincipal();
    	
    	boolean isAuthenticated();
    
    	void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    Authentication 继承自 Principal,而 PrincipalJava 提供的

    Authentication 是请求认证成功后的令牌,里面包含了认证主体 Principal 和授权信息 Authorities。知道了这两个概念以后,接下来我们看一下 SecurityContextHolder

    SecurityContextHolder

    public class SecurityContextHolder {
    
    	// 预设 3 种模式
    	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);
    
    	// SecurityContext 的持有策略接口,也就是上面 3 中模式的功能接口定义
    	private static SecurityContextHolderStrategy strategy;
    
    	// 初始化次数
    	private static int initializeCount = 0;
    
    	// 1、第一步,会执行 initialize 方法
    	static {
    		initialize();
    	}
    
    	private static void initialize() {
    		if (!StringUtils.hasText(strategyName)) {
    			// Set default
    			// 默认会设置为这种策略
    			strategyName = MODE_THREADLOCAL;
    		}
    		if (strategyName.equals(MODE_THREADLOCAL)) {
    			strategy = new ThreadLocalSecurityContextHolderStrategy();
    		}
    		else if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {
    			strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
    		}
    		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++;
    	}
    	
    	// 下面几个方式是定义的操作 SecurityContext 的方法,主要是对 SecurityContext 的增删改查
    	public static void clearContext() {
    		strategy.clearContext();
    	}
    
    	public static SecurityContext getContext() {
    		return strategy.getContext();
    	}
    
    	public static int getInitializeCount() {
    		return initializeCount;
    	}
    
    	public static void setContext(SecurityContext context) {
    		strategy.setContext(context);
    	}
    
    	public static void setStrategyName(String strategyName) {
    		SecurityContextHolder.strategyName = strategyName;
    		initialize();
    	}
    
    	public static SecurityContextHolderStrategy getContextHolderStrategy() {
    		return strategy;
    	}
    	public static SecurityContext createEmptyContext() {
    		return strategy.createEmptyContext();
    	}
    
    	@Override
    	public String toString() {
    		return "SecurityContextHolder[strategy='" + strategyName + "'; initializeCount=" + initializeCount + "]";
    	}
    
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89

    SecurityContextHolder 的源码中我们知道默认是使用 ThreadLocalSecurityContextHolderStrategy 这种模式,也就是说底层是使用 ThreadLocal 来存储 SecurityContext 的。

    final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
    
    	private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<>();
    
    	@Override
    	public void clearContext() {
    		contextHolder.remove();
    	}
    
    	@Override
    	public SecurityContext getContext() {
    		SecurityContext ctx = contextHolder.get();
    		if (ctx == null) {
    			ctx = createEmptyContext();
    			contextHolder.set(ctx);
    		}
    		return ctx;
    	}
    
    	@Override
    	public void setContext(SecurityContext context) {
    		Assert.notNull(context, "Only non-null SecurityContext instances are permitted");
    		contextHolder.set(context);
    	}
    
    	@Override
    	public SecurityContext createEmptyContext() {
    		return new SecurityContextImpl();
    	}
    
    }
    
    • 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

    源码比较简单,没什么内容,就不做过多介绍了。

    总结

    以上就是关于 SecurityContextHolder 的相关源码阅读,通过分析我们知道:

    • SecurityContextHolder 为每一个执行中的线程关联了 SecurityContext
    • 在认证通过之后,应该通过 SecurityContextHolder 来设置 SecurityContext
    • 我们可以指定 SecurityContext 的存储策略,也可以自定义存储策略
  • 相关阅读:
    零基础学python之列表
    uniapp打包微信小程序。报错:https://api.weixin.qq.com 不在以下 request 合法域名列表
    学习C++语言可以适用于哪些方面
    Unity引擎更新收费模式:从收入分成转向游戏安装量,将会有哪些影响呢
    机器学习笔记之贝叶斯线性回归(二)推断任务推导过程
    联合阿里p8测试开发耗时一个月整理的全套从0开始到功能测试再到自动化测试再进阶测试开发学习路线图
    物联网(IoT)课程
    Reactor反应堆:EventLoop的执行流程
    rabbitmq
    Python进阶复习-Pandas库
  • 原文地址:https://blog.csdn.net/qiaohao0206/article/details/126473498