spring-security源码-Filter之WebAsyncManagerIntegrationFilter(十)
1.Spring-Security系列导航2.spring-security使用-登录(一)3.spring-security使用-自定义数据源(二)4.spring-security使用-更友好的方式扩展登录AuthenticationProvider(三)5.spring-security使用-获得当前用户信息(四)6.spring-security使用-同一个账号只允许登录一次(五)7.spring-security使用-session共享(六)8.spring-security使用-安全防护HttpFirewall(七)9.spring-security使用-权限控制(八)10.spring-security源码-初始化(九)11.spring-security源码-如何初始化SecurityFilterChain到Servlet12.spring-security源码-FilterChainProxy
13.spring-security源码-Filter之WebAsyncManagerIntegrationFilter(十)
14.Spring-security源码-Filter之SecurityContextPersistenceFilter(十一)15.Spring-security源码-Filter之HeaderWriterFilter(十二)16.Spring-security源码-Filter之LogoutFilter(十三)17.Spring-security源码-Filter之UsernamePasswordAuthenticationFilter(十四)18.Spring-security源码-Filter之ConcurrentSessionFilter(十五)19.Spring-security源码-Filter之SessionManagementFilter(十六)20.Spring-security源码-Filter之RememberMeAuthenticationFilter(十七)21.Spring-security源码-Filter之ExceptionTranslationFilter(十八)22.Spring-security源码-Filter之FilterSecurityInterceptor(十九)23.Spring-security源码-注解权限原理(二十)24.Spring-security源码-注解权限原理之MethodSecurityInterceptor(二十一)25.Spring-Security基于源码扩展-一套系统多套登录逻辑(二十二)26.Spring-Security基于源码扩展-自定义登录(二十三)27.Spring-Security基于源码扩展-自定义认证失败返回(二十四)28.Spring-Security基于源码扩展-自定义授权注解(二十五)作用
我们获取当前登录用户信息是根据SecurityContextHolder.getContext()获取的,SecurityContextHolder.getContext()本质是ThreadLocal实现
Spring MVC WebAsyncTask是异步另外一个线程 所以用于保证我们在Task 线程也能通过SecurityContextHolder.getContext()获取
WebAsyncTask简单例子
GetMapping("/completion") public WebAsyncTask<String> asyncTaskCompletion() { // 打印处理线程名 out.println(format("请求处理线程:%s", currentThread().getName())); // 模拟开启一个异步任务,超时时间为10s WebAsyncTask<String> asyncTask = new WebAsyncTask<>(10 * 1000L, () -> { out.println(format("异步工作线程:%s", currentThread().getName())); // 任务处理时间5s,不超时 sleep(5 * 1000L); return asyncService.generateUUID(); }); // 任务执行完成时调用该方法 asyncTask.onCompletion(() -> out.println("任务执行完成")); out.println("继续处理其他事情"); return asyncTask; }
输出
请求处理线程:http-nio-8080-exec-2
继续处理其他事情
异步工作线程:MvcAsync1
任务执行完成
初始化处
private void applyDefaultConfiguration(HttpSecurity http) throws Exception { //http本质也是build 这里都是配置默认的config configure add CsrfConfigurer http.csrf(); //默认增加一个WebAsyncManagerIntegrationFilter http.addFilter(new WebAsyncManagerIntegrationFilter()); //configures add ExceptionHandlingConfigurer http.exceptionHandling(); //configures add HeadersConfigurer http.headers(); //configures add SessionManagementConfigurer http.sessionManagement(); //configure add SecurityContextConfigurer http.securityContext(); //configure add RequestCacheConfigurer http.requestCache(); ///configure add AnonymousConfigurer http.anonymous(); ///configure add ServletApiConfigurer http.servletApi(); //configure DefaultLoginPageConfigurer http.apply(new DefaultLoginPageConfigurer<>()); //configure LogoutConfigurer http.logout(); }
WebAsyncManagerIntegrationFilter
public final class WebAsyncManagerIntegrationFilter extends OncePerRequestFilter { private static final Object CALLABLE_INTERCEPTOR_KEY = new Object(); public WebAsyncManagerIntegrationFilter() { } protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException { //获取WebAsync 异步管理器 WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); //如果没有初始化SecurityContextCallableProcessingInterceptor SecurityContextCallableProcessingInterceptor securityProcessingInterceptor = (SecurityContextCallableProcessingInterceptor)asyncManager.getCallableInterceptor(CALLABLE_INTERCEPTOR_KEY); if (securityProcessingInterceptor == null) { //则手动创建Spring Security的SecurityContextCallableProcessingInterceptor //<1>核心原理应该是在开启异步的时候通过拦截器 设置当前Context asyncManager.registerCallableInterceptor(CALLABLE_INTERCEPTOR_KEY, new SecurityContextCallableProcessingInterceptor()); } filterChain.doFilter(request, response); } }
<1>
public final class SecurityContextCallableProcessingInterceptor extends CallableProcessingInterceptorAdapter { private volatile SecurityContext securityContext; public SecurityContextCallableProcessingInterceptor() { } public SecurityContextCallableProcessingInterceptor(SecurityContext securityContext) { Assert.notNull(securityContext, "securityContext cannot be null"); this.setSecurityContext(securityContext); } public <T> void beforeConcurrentHandling(NativeWebRequest request, Callable<T> task) { if (this.securityContext == null) { // before 开启Task之前设置SecurityContext this.setSecurityContext(SecurityContextHolder.getContext()); } } public <T> void preProcess(NativeWebRequest request, Callable<T> task) { //负责Task线程写入 SecurityContextHolder.setContext(this.securityContext); } public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) { //负责Task线程清空 SecurityContextHolder.clearContext(); } private void setSecurityContext(SecurityContext securityContext) { this.securityContext = securityContext; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!