Spring Security新线程为什么获取不到用户信息-续1
大家好,我是欧阳方超,微信公众号同名。
1 概述
除了手动传递SecurityContext之外,还可以使用代理线程DelegatingSecurityContextExecutorService来执行异步任务,这样可以将父线程的securityConext传播到异步线程中。
2 创建 DelegatingSecurityContextExecutorService Bean
在基于 Spring 的应用中,我们可以创建一个DelegatingSecurityContextExecutorService的 Bean,以便在CompletableFuture中使用它来自动处理SecurityContext的传递。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.concurrent.DelegatingSecurityContextExecutorService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
@Configuration
public class AsyncSecurityConfig {
// 创建一个基础的线程池
@Bean
public ExecutorService baseExecutorService() {
return Executors.newFixedThreadPool(10);
}
// 创建 DelegatingSecurityContextExecutorService Bean
@Bean
public DelegatingSecurityContextExecutorService delegatingSecurityContextExecutorService(ExecutorService baseExecutorService) {
return new DelegatingSecurityContextExecutorService(baseExecutorService);
}
}
在上述代码中,首先创建了一个基础的ExecutorService,这里使用了Executors.newFixedThreadPool(10)创建了一个固定大小为 10 的线程池。然后,将这个基础的线程池注入到DelegatingSecurityContextExecutorService的构造函数中,创建了DelegatingSecurityContextExecutorService Bean。这个DelegatingSecurityContextExecutorService会在每个任务执行时,自动从当前线程获取SecurityContext并设置到执行任务的线程中。
3 在 CompletableFuture 中使用 DelegatingSecurityContextExecutorService
假设有一个服务层方法,需要在异步操作中访问当前用户的信息(存储在SecurityContext中),可以这样使用CompletableFuture和DelegatingSecurityContextExecutorService:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Delayed;
import java.util.concurrent.TimeUnit;
@Service
public class MyService {
@Autowired
private DelegatingSecurityContextExecutorService delegatingSecurityContextExecutorService;
public CompletableFuture<String> doAsyncOperation() {
CompletableFuture.runAsync(() -> {
SecurityContextHolder.setContext(currentContext);
// 在这里执行需要安全上下文的操作
}, delegatingSecurityContextExecutorService);
}
}
在上述MyService类中,我们注入了DelegatingSecurityContextExecutorService。在doAsyncOperation方法中,我们使用CompletableFuture.supplyAsync创建了一个异步任务,并指定了DelegatingSecurityContextExecutorService作为执行器。这样,在异步任务内部,我们可以安全地获取SecurityContext并进行相应的操作,无需手动传递SecurityContext。
4 总结
通过创建DelegatingSecurityContextExecutorService Bean 并在CompletableFuture中使用它,能够优雅地解决CompletableFuture异步任务中SecurityContext的传递问题。这种自动传递机制与手动传递方式相比,大大简化了代码逻辑,减少了因手动处理不当而导致安全漏洞的风险,提高了应用的安全性和可维护性。
我是欧阳方超,把事情做好了自然就有兴趣了,如果你喜欢我的文章,欢迎点赞、转发、评论加关注。我们下次见。