新线程中获取Spring Security认证信息

在做一些耗时的操作逻辑时,经常会通过开启新线程进行处理。但是,直接通过new Thread()/new Runnable() 方式创建的线程中没有用户的认证信息(即SecurityContextHolder.getContext().getAuthentication() 返回的是 null)。这是由于 认证信息 是在请求到达后台,经由 Security 的一系列过滤器后将 认证信息写入到 线程本地变量中。所以,新开的线程并没有执行过滤器的逻辑,自然没有认证信息。
既然不会自动设置认证信息,那我们只有手动设置认证信息了。

方式一: 手动设置线程中的认证信息

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

// 新线程
Runnable runnable = new Runnable() {
	public void run() {
		// 手动设置线程中的认证信息
		SecurityContextHolder.getContext().setAuthentication(authentication);
		
		// 线程处理逻辑(后续就能获取到认证信息)
		...
	}
};
new Thread(runnable).start();

方式二:使用 DelegatingSecurityContextRunnable 创建线程

官方文档:https://docs.spring.io/spring-security/site/docs/5.0.16.RELEASE/reference/htmlsingle/#delegatingsecuritycontextrunnable

Spring Security 考虑到了新线程需要访问认证信息的情况,提供了 DelegatingSecurityContextRunnable 类,通过该类构建新线程(Runnable),线程内部自然能获取认证信息。
查看DelegatingSecurityContextRunnable的源码, 你会发现,本质上思路和方式一是一致的。

Runnable runnable = new DelegatingSecurityContextRunnable(() -> {
  // 线程处理逻辑
  ...
});
new Thread(runnable).start();

或者

Runnable runnable = DelegatingSecurityContextRunnable.create(() -> {
  //线程处理逻辑
  ...
}, SecurityContextHolder.getContext());
new Thread(runnable).start();

另:
Spring Security 提供一个线程池DelegatingSecurityContextExecutor,线程池类所有线程公用一个认证信息。如果是执行比较通用的逻辑,并不涉及个人的认证信息。其应该是一个比较好的方案。

官方文档:https://docs.spring.io/spring-security/site/docs/5.0.16.RELEASE/reference/htmlsingle/#delegatingsecuritycontextexecutor

reference:
官方文档:Spring Security 对并发的支持


end

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值