Java21 + SpringBoot3使用Spring Security时如何在子线程中获取到认证信息
前言
近日心血来潮想做一个开源项目,目标是做一款可以适配多端、功能完备的模板工程,包含后台管理系统和前台系统,开发者基于此项目进行裁剪和扩展来完成自己的功能开发。本项目为前后端分离开发,后端基于Java21和SpringBoot3开发,后端使用Spring Security、JWT、Spring Data JPA等技术栈,前端提供了vue、angular、react、uniapp、微信小程序等多种脚手架工程。
项目地址:https://gitee.com/breezefaith/fast-alden
在使用Spring Security时,笔者定义了一个ThreadPoolTaskExecutorBean用于创建子线程,但是却遇到了子线程中无法获取到认证信息的问题,本文主要介绍该问题的解决方案。
原因分析
在 Spring Security中想要获取登录用户信息,只能在当前线程中获取,不能在子线程中获取,其中一个重要的原因就是SecurityContextHolder默认将用户信息保存在ThreadLocal中。
ThreadLocal叫做本地线程变量,意思是说,ThreadLocal中填充的的是当前线程的变量,该变量对其他线程而言是封闭且隔离的,ThreadLocal为变量在每个线程中创建了一个副本,这样每个线程都可以访问自己内部的副本变量。
解决方案
方案1:手动设置线程中的认证信息
在子线程的业务逻辑代码之前先手动设置认证信息,后续就可以通过SecurityContextHolder直接获取。
// 获取当前线程认证信息
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// 创建新线程
Runnable runnable = new Runnable() {
public void run() {
// 手动设置线程中的认证信息
SecurityContextHolder.getContext().setAuthentication(authentication);
// 线程处理逻辑(后续就能获取到认证信息)
// ...
}
};
new Thread(runnable).start();
方案2:使用DelegatingSecurityContextRunnable创建线程
Spring Security考虑到了新线程需要访问认证信息的情况,提供了DelegatingSecurityContextRunnable类,通过该类构建新线程(返回一个Runnable对象),线程内部自然能获取认证信息。有兴趣的读者可以阅读一下DelegatingSecurityContextRunnable的源码,其思路与方法1是一致的,都是先获取到当前线程的认证信息,然后传递给新线程。
// 使用DelegatingSecurityContextRunnable创建线程
Runnable runnable = new DelegatingSecurityContextRunnable(() -> {
// 线程处理逻辑
// ...
});
new Thread(runnable).start();
方案3:修改Spring Security安全策略
默认情况下,Spring Security使用ThreadLocal存储认证信息,但实际上它也支持通过设置安全策略来修改认证信息的存储位置,它支持三种安全策略,有MODE_THREADLOCAL、MODE_INHERITABLETHREADLOCAL和MODE_GLOBAL。如果没有指定,则会默认使用MODE_THREADLOCAL策略。
MODE_THREALOCAL表示用户信息只能由当前线程访问。MODE_INHERITABLETHREADLOCAL表示用户信息可以由当前线程及其子线程访问.。MODE_GLOBAL表示用户信息没有线程限制,全局都可以访问,一般用于gui的开发中。
因此,将安全策略修改为MODE_INHERITABLETHREADLOCAL就可以在子线程中获取到认证信息。
Spring Security还提供了两种修改安全策略的方式,一种是通过设置JVM参数spring.security.strategy,一种是调用SecurityContextHolder的setStrategyName方法。
通过设置JVM参数修改安全策略
-Dspring.security.strategy=MODE_INHERITABLETHREADLOCAL

通过SecurityContextHolder修改安全策略
可以借助@PostConstruct注解在程序启动后修改安全策略。
@Configuration
public class CommonSecurityConfig {
@PostConstruct
public void setStrategyName() {
// 程序启动后修改认证信息上下文存储策略,支持子线程中获取认证信息
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
}
}
@PostConstruct注解是由Java提供的,它用来修饰一个非静态的void方法。它会在服务器加载Servlet的时候运行,并且只运行一次。
总结
本文主要介绍SpringBoot3使用Spring Security时如何在子线程中获取到认证信息。如有错误,还望批评指正。
在后续实践中我也是及时更新自己的学习心得和经验总结,希望与诸位看官一起进步。
Java21 + SpringBoot3使用Spring Security时如何在子线程中获取到认证信息的更多相关文章
- C# 最基本的涉及模式(单例模式) C#种死锁:事务(进程 ID 112)与另一个进程被死锁在 锁 | 通信缓冲区 资源上,并且已被选作死锁牺牲品。请重新运行该事务,解决方案: C#关闭应用程序时如何关闭子线程 C#中 ThreadStart和ParameterizedThreadStart区别
C# 最基本的涉及模式(单例模式) //密封,保证不能继承 public sealed class Xiaohouye { //私有的构造函数,保证外部不能实例化 private ...
- SpringBoot + Spring Security 学习笔记(三)实现图片验证码认证
整体实现逻辑 前端在登录页面时,自动从后台获取最新的验证码图片 服务器接收获取生成验证码请求,生成验证码和对应的图片,图片响应回前端,验证码保存一份到服务器的 session 中 前端用户登录时携带当 ...
- Spring Security 是如何在 Servlet 应用中执行的?
Spring Security 是一个强大的认证和授权框架,它的使用方式也非常简单,但是要想真正理解它就需要花一时间来学习了,最近在学习 Spring Security 时有一些新的理解,特意记录下来 ...
- spring源码 — 二、从容器中获取Bean
getBean 上一节中说明了容器的初始化,也就是把Bean的定义GenericBeanDefinition放到了容器中,但是并没有初始化这些Bean.那么Bean什么时候会初始化呢? 在程序第一个主 ...
- 如何在线程中获取spring 管理的bean
转载自:https://my.oschina.net/skyline520/blog/181158?fromerr=GjtR6Wec spring xml中定义 <!--spring 工具类-- ...
- Spring Security入门(3-4)Spring Security 异常处理、异常传递和异常获取
- Spring Security怎样不让默认的ProviderManager清除密码等信息
<authentication-manager erase-credentials="false"> ... </authentication-manager&g ...
- spring security在spring mvc的action中获取登录人信息
@RequestMapping("/index") public ModelAndView login( @RequestParam(value = "error&quo ...
- ajax异步处理时,如何在JS中获取从Servlet或者Action中session,request
ssh项目中,我需要登陆某个页面(如a.jsp),通过onblur()鼠标失去焦点后来触发js函数(函数是ajax请求)请求到相应的action,处理完成后将数据存放到session对象里面,然后在a ...
- Spring Security 案例实现和执行流程剖析
Spring Security Spring Security 是 Spring 社区的一个顶级项目,也是 Spring Boot 官方推荐使用的安全框架.除了常规的认证(Authentication ...
随机推荐
- off-policy RL | Advantage-Weighted Regression (AWR):组合先前策略得到新 base policy
论文题目:Advantage-Weighted Regression: Simple and Scalable Off-Policy Reinforcement Learning,ICLR 2020 ...
- Spring boot 自定义kafkaTemplate的bean实例进行生产消息和发送消息
本文为博主原创,未经允许不得转载: 目录: 1. 自定义生产消息 kafkaTemplate 实例 2. 封装 kafka 发送消息的service 方法 3. 测试 kafka 发送消息ser ...
- 基于AHB_BUS的eflash控制器设计-02
基于AHB-BUS的eflash控制器设计 1.Flash Spec 1.1 地址映射 XADR是10bit?因为一共有1024行 每一行128byte容量,每次读取的粒度就是一个double wor ...
- grpc-环境与示例
1. 数据传输基本原理 2. grpc环境安装 代码生成器 go get -u github.com/golang/protobuf/protoc-gen-go // 会自动在 $GOPATH/bin ...
- [转帖]深度硬核文:Nginx的301重定向处理过程分析
https://zhuanlan.zhihu.com/p/84539204 本文首发于公众号:js-mindmap 一,序言 "晚上九点,办公室里烟雾缭绕,工作进度依然没有什么进展.王二胖打 ...
- [转帖]警惕Oracle数据库性能“隐形杀手”——Direct Path Read
一. 简介 Oracle 的11g版本正式发布到今天已经10年有余,最新版本也已经到了20c,但是Direct Path Read(直接路径读)导致性能问题的案例仍时有发生,很多12c的用户还是经常遇 ...
- [转帖]elasticsearch-create-enrollment-tokenedit
https://www.elastic.co/guide/en/elasticsearch/reference/current/create-enrollment-token.html The ela ...
- [转帖]Redhat、CentOS添加静态路由的方法
https://www.diewufeiyang.com/post/1174.html 我们经常遇到需要在系统默认路由的基础上,额外添加静态路由的需求.为了使得下次系统启动这些静态路由依旧生效,我们可 ...
- [转帖]Kafka-Kraft 模式架构部署
news文章来源: Kafka-Kraft 模式架构部署 Kafka网址:https://kafka.apache.org/ PS:因环境原因此文档内端口都有修改! 1.去官网下载二进制包 PS:3. ...
- [转帖]CoreDump设置方式
https://www.jianshu.com/p/f5c3134072d2 本文讲述利用coredump调试时,对coredump信息相关的设置方式. 设置core文件大小 列出所有资源的限制 #u ...
