最近使用ruoyi框架的时候发现异步线程中无法获取用户信息的问题,现已解决<br>
原因:
Spring Security中的上下文SecurityContext的管理策略SecurityContextHolderStrategy有三种:
public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";
public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";
public static final String MODE_GLOBAL = "MODE_GLOBAL";
默认的管理策略是:MODE_THREADLOCAL,对应ThreadLocalSecurityContextHolderStrategy
# 初始化方法
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 var2) {
ReflectionUtils.handleReflectionException(var2);
}
}
++initializeCount;
}
ThreadLocalSecurityContextHolderStrategy里保存context的方式是ThreadLocal,使用threadlocal子线程并不能获取父类线程的ThreadLocalMap,所以就导致了问题
private static final ThreadLocal<SecurityContext> contextHolder = new ThreadLocal();
解决方法:
更改context的管理策略SecurityContextHolderStrategy为MODE_INHERITABLETHREADLOCAL,即
InheritableThreadLocalSecurityContextHolderStrategy,里面保存context的方式是InheritableThreadLocal,这时子线程就可以获取父类线程threadlocalMap了
private static final ThreadLocal<SecurityContext> contextHolder = new InheritableThreadLocal();
代码:
- 1、可以在配置Security的配置类中添加Bean
@Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
methodInvokingFactoryBean.setTargetMethod("setStrategyName");
methodInvokingFactoryBean.setArguments((Object) new String[]{SecurityContextHolder.MODE_INHERITABLETHREADLOCAL});
return methodInvokingFactoryBean;
}
- 2、可以在配置Security的配置类中添加类初始化方式 ,会在注入SecurityContextHolder之后调用其中静态方法更改SecurityContextHolderStrategy的实现类
@PostConstruct
public void setStrategyName(){
SecurityContextHolder.setStrategyName(
SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
}
- 3、可以在启动项加上-Dspring.security.strategy=MODE_INHERITABLETHREADLOCAL