我使用@Async
异步调用了Spring的一个方法。这个方法调用了另一个用@PreAuthorize
标注的方法,Spring Security Annotation。为了使授权工作,我必须将SecurityContextHolder
模式设置为MODE_INHERITABLETHREADLOCAL
,以便将身份验证信息传递给异步调用。到目前为止,一切工作正常。
然而,当我注销并以另一个用户身份登录时,SecurityContextHolder在异步方法中存储已注销的旧用户的身份验证信息。这当然会导致不希望的AccessDenied
异常。同步调用则没有这样的问题。
我已经定义了<task:executor id="executors" pool-size="10"/>
,那么一旦执行器池中的线程被初始化,它将不会覆盖身份验证信息,这是否是一个问题?
8条答案
按热度按时间svdrlsy41#
我猜
MODE_INHERITABLETHREADLOCAL
不能正确地与线程池一起工作。作为一种可能的解决方案,您可以尝试将
ThreadPoolTaskExecutor
子类化,并覆盖其方法以手动传播SecurityContext
,然后声明该执行器而不是<task:executor>
,如下所示:plupiseo2#
我 也 遇到 了 这个 问题 。 使用
DelegatingSecurityContextAsyncTaskExecutor
正确 配置 ThreadPoolTaskExecutor 是 很 重要 的 。 调用 initialize ( ) 方法 也 是 很 重要 的 , 否则 会 抛出 错误 。中 的 每 一 个
业务 逻辑 中 异步 调用 的 方法 :
格式
然而 , 在 某些 情况 下 , 您 可能 还 想 委托 其他 线程 信息 , 如 MDC 上下文 或 请求 上下文 , 或者 您 只是 想 对 如何 将 内容 传递 给 执行器 线程 拥有 更多 控制 权 。 如果 是 这种 情况 , 您 可以 手动 将 本地 线程 信息 绑定 到 执行器 线程 。 如何 实现 这 一 点 的 思想 已经 在@axtavt 的 答案 中 描述 过 了 。但是 我们 现在 可以 使用 TaskDecorator 以 更 优雅 的 方式 来 完成 它 。 TaskDecorator 将 请求 线程 的 上下文 存储 在 变量 中 , 并 将 它们 绑定 在 闭包 中 , 以便 可以 在 执行器 线程 中 访问 上下文 。 当 线程 执行 完成 时 , 上下文 将 从 执行器 线程 中 清除 ,以便 在 重用 线程 时 信息 消失 。
格式
在 TaskExecutor 创建 期间 , TaskDecorator 被 分配 给 TaskExecutor ( 使用 setTaskDecorator 方法 ) 。
格式
您 也 可以 将 这 两 种 方法 结合 起来 ( 例如 , 使用 TaskDecorator 复制 MDC 上下文 , 但 仍然 使用 DelegatingSecurityContextAsyncTaskExecutor 复制 安全 上下文 ) , 但 我 不 建议 这样 做 , 因为 这 会 增加 复杂 性 。 如果 您 使用 TaskDecorator , 您 还 可以 使用 它 设置 安全 上下文 , 如果 您 只 需要 设置 安全 上下文 , 则 只需 使用 DelegatingSecurityContextAsyncTaskExecutor 方法 。
ycl3bljg3#
这只是一个提示,需要进一步调查(我太累了,但也许有人会发现这对未来的调查有用):
今天我偶然发现了
org.springframework.security.task.DelegatingSecurityContextAsyncTaskExecutor
请参阅GitHub。它看起来像是被设计来委托安全上下文,以便通过
@Async
调用“传递”安全上下文。也看看这个帖子:Spring Security 3.2 M1 Highlights, Servlet 3 API Support听起来似乎是强相关的。
tv6aics14#
根据拉尔夫和奥克提供的信息-
如果您想让@Async使用标准的任务执行者标记,您可以像这样设置SpringXML配置
然后,在@Async方法中,指定要使用的池
这样,无论何时调用@Async方法,线程池线程都将使用与调用线程相同的安全上下文
esyap4oy5#
如前所述,对于池化线程环境,应使用
DelegatingSecurityContextAsyncTaskExecutor
,而不是MODE_INHERITABLETHREADLOCAL
(请阅读此处)。为Sping Boot 项目保留简单的
DelegatingSecurityContextAsyncTaskExecutor
配置,这些项目将简单地使用异步任务的默认Spring Boot池:ao218c7q6#
基于@Ralph答案,可以通过
Spring
和threadpooling
实现Aync event
,并使用http://docs.spring.io/autorepo/docs/spring-security/4.0.0.M1/apidocs/org/springframework/security/task/DelegatingSecurityContextAsyncTaskExecutor.html委托安全性示例代码
o75abkj47#
如果要添加到@axtavt的答案中,您也会希望覆盖其他方法。
w41d8nur8#
我使用带有JNDI管理的线程池的企业级Jboss服务器;这就是我的工作: