我使用 Spring 异步调用一个方法,使用 @Async
.这个方法调用另一个用 @PreAuthorize
注释的方法。 ,Spring 安全注解。为了使授权工作,我必须设置 SecurityContextHolder
模式为 MODE_INHERITABLETHREADLOCAL
,以便将身份验证信息传递给异步调用。到目前为止一切正常。
但是,当我注销并以其他用户身份登录时,SecurityContextHolder 在异步方法中存储已注销的旧用户的身份验证信息。它当然会导致不需要的 AccessDenied
异常(exception)。同步调用不存在这样的问题。
我已经定义了<task:executor id="executors" pool-size="10"/>
, 那么执行器池中的线程一旦初始化就不会覆盖身份验证信息,这可能是一个问题吗?
最佳答案
我猜MODE_INHERITABLETHREADLOCAL
不能与线程池一起正常工作。
作为一种可能的解决方案,您可以尝试继承 ThreadPoolTaskExecutor
并覆盖其传播方法SecurityContext
手动,然后声明该执行程序而不是 <task:executor>
,类似这样:
public void execute(final Runnable r) {
final Authentication a = SecurityContextHolder.getContext().getAuthentication();
super.execute(new Runnable() {
public void run() {
try {
SecurityContext ctx = SecurityContextHolder.createEmptyContext();
ctx.setAuthentication(a);
SecurityContextHolder.setContext(ctx);
r.run();
} finally {
SecurityContextHolder.clearContext();
}
}
});
}
关于Spring Security 和 @Async(经过身份验证的用户混在一起),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5246428/