• springsecurity源码Filter之WebAsyncManagerIntegrationFilter(十)


    作用

    我们获取当前登录用户信息是根据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
    任务执行完成

    初始化处

    参考《spring-security源码-初始化(九)》

    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;
        }
    }
  • 相关阅读:
    MySQL
    php抽象类和接口
    php面向对象三大特征
    php面向对象
    Git
    css3属性
    数据渲染
    ajax(2)
    ajax笔记
    作用域面试题
  • 原文地址:https://www.cnblogs.com/LQBlog/p/15528683.html
Copyright © 2020-2023  润新知