SpringSecurity 中的 SecurityContextHolder 分析
分析
一般我们在 SpringSecurity 中可以通过 SecurityContextHolder.getContext().getAuthentication()获取到认证信息,这个认证信息就是存放在 SecurityContext 中,这个 SecurityContext 就是通过 SecurityContextHolder.getContext()获取到的,SecurityContextHolder.getContext()的代码如下
1 2 3
| public static SecurityContext getContext() { return strategy.getContext(); }
|
上面的这个 strategy 是根据具体的策略来确定到底从哪获取 SecurityContext,这个 strategy 的初始化代码
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
| static { initialize(); }
private static void initialize() { if (!StringUtils.hasText(strategyName)) { 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 { Class<?> clazz = Class.forName(strategyName); Constructor<?> customStrategy = clazz.getConstructor(); strategy = (SecurityContextHolderStrategy) customStrategy.newInstance(); } catch (Exception ex) { ReflectionUtils.handleReflectionException(ex); } }
initializeCount++; }
|
ThreadLocal 模式下的使用的是 ThreadLocalSecurityContextHolderStrategy 这个类的对象来存储 SecurityContext
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
| final class ThreadLocalSecurityContextHolderStrategy implements SecurityContextHolderStrategy {
private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal<>();
public void clearContext() { contextHolder.remove(); }
public SecurityContext getContext() { SecurityContext ctx = contextHolder.get();
if (ctx == null) { ctx = createEmptyContext(); contextHolder.set(ctx); }
return ctx; }
public void setContext(SecurityContext context) { Assert.notNull(context, "Only non-null SecurityContext instances are permitted"); contextHolder.set(context); }
public SecurityContext createEmptyContext() { return new SecurityContextImpl(); } }
|
接下来再看下全局模式对应的 GlobalSecurityContextHolderStrategy 的代码
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
| final class GlobalSecurityContextHolderStrategy implements SecurityContextHolderStrategy { private static SecurityContext contextHolder;
public void clearContext() { contextHolder = null; }
public SecurityContext getContext() { if (contextHolder == null) { contextHolder = new SecurityContextImpl(); }
return contextHolder; }
public void setContext(SecurityContext context) { Assert.notNull(context, "Only non-null SecurityContext instances are permitted"); contextHolder = context; }
public SecurityContext createEmptyContext() { return new SecurityContextImpl(); } }
|
那个可继承 ThreadLocal 用得比较少,应该和和上面的 ThradLocal 差不多,感兴趣的可以去网上查一下,这里就不分析了
总结
- SecurityContextHolder 的作用是保存 SecurityContext
- SecurityContextHolder 默认使用的是 ThreadLocal 模式来保存 SecurityContext,在这种模式下同一个线程获取到 SecurityContext 都是一样的,如果是全局模式下,所有的线程获取到的 SecurityContext 都是同一个,如果需要使用其它模式可以通过调用 SecurityContextHolder.setStrategyName 方法来设置