Kai*_*kun 2 multithreading asynchronous spring-mvc spring-boot spring-cloud-feign
我将 Async 与使用 Feign 调用远程服务的方法一起使用,我需要将 oauth2 令牌附加到请求中,为此我使用了 RequestInterceptor。
@Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return requestTemplate -> {
Object principal = SecurityContextHolder
.getContext()
.getAuthentication()
.getPrincipal();
if (!principal.equals("anonymousUser")) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)
SecurityContextHolder.getContext().getAuthentication().getDetails();
requestTemplate.header("Authorization", "bearer " + details.getTokenValue());
}
};
}
Run Code Online (Sandbox Code Playgroud)
但是当 requestInterceptor 在另一个线程中使用时,我无法访问相同的安全上下文,因此 getAuthentication 返回 null。
我尝试在执行程序配置中修复它,我创建了一个 DelegatingSecurityContextExecutor 来包装执行程序和安全上下文。但似乎 bean 是在“主”线程中创建的,并且安全上下文与当时使用的安全上下文不同,当执行 RestController 方法时,因此 getAuthentication() 仍然返回 null。
@Bean(name = "asyncExecutor")
public Executor asyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(3);
executor.setMaxPoolSize(3);
executor.setQueueCapacity(100);
executor.setThreadNamePrefix("AsynchThread-");
executor.initialize();
Executor wrappedExecutor = new DelegatingSecurityContextExecutor(executor, SecurityContextHolder.getContext());
return wrappedExecutor;
}
Run Code Online (Sandbox Code Playgroud)
如何以正确的方式配置执行程序?
我终于找到了解决方案,可以将安全上下文自动传播到其他线程。
只需在 Spring Boot 应用程序的静态 main 方法中添加这行代码:
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
Run Code Online (Sandbox Code Playgroud)
解决方案在这里得到了很好的解释:https : //www.baeldung.com/spring-security-async-principal-propagation?fbclid=IwAR1zeGKvRvBb7GG8SmxO4x8-NlKkG39Q29WoLKxZ8NRzyKEcnDWx4Q6EUk0
!! 警告 !!:我注意到该解决方案的意外行为,至少在我的本地开发环境中。我使用 chrome 的 sessionbox 工具通过两个不同的帐户连接到我的应用程序(与不同的浏览器相同),似乎当我与用户 A SecurityContextHolder.getContext().getAuthentication().getPrincipal() 连接时返回用户 B 的安全上下文......如此巨大的安全问题!我目前正在寻找解决方案。
阅读这篇文章:如何设置 Spring Security SecurityContextHolder 策略?解决方案似乎在这里Spring Security 和 @Async(经过身份验证的用户混淆)