1、作用
- • 是为了接口返回异步对象,然后执行异步任务也能通过SecurityContextHolder获取SecurityContext
- • 比如说返回值是WebAsyncTask的时候
2、WebAsyncManagerIntegrationFilter
- • 源码很短就是在WebAsyncManager中注册了SecurityContextCallableProcessingInterceptor
public final class WebAsyncManagerIntegrationFilter extends OncePerRequestFilter {
private static final Object CALLABLE_INTERCEPTOR_KEY = new Object();
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
//获得Web异步管理器
WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
SecurityContextCallableProcessingInterceptor securityProcessingInterceptor = (SecurityContextCallableProcessingInterceptor) asyncManager
.getCallableInterceptor(CALLABLE_INTERCEPTOR_KEY);
if (securityProcessingInterceptor == null) {
//重点就是注册了一个这个拦截器
asyncManager.registerCallableInterceptor(CALLABLE_INTERCEPTOR_KEY,
new SecurityContextCallableProcessingInterceptor());
}
filterChain.doFilter(request, response);
}
}
- • WebAsyncManagerIntegrationFilter没有对应的配置类,是在获取HttpSecurity的时候,默认注册的拦截器
3、AsyncTaskMethodReturnValueHandler
- • 当接口返回值是WebAsyncTask的时候,SpringMVC会适配AsyncTaskMethodReturnValueHandler作为返回值处理器
- • 可以看出就是调用了WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer);来处理
@Override
public void handleReturnValue(@Nullable Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue == null) {
mavContainer.setRequestHandled(true);
return;
}
WebAsyncTask<?> webAsyncTask = (WebAsyncTask<?>) returnValue;
if (this.beanFactory != null) {
webAsyncTask.setBeanFactory(this.beanFactory);
}
WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(webAsyncTask, mavContainer);
}
- • 而startCallableProcessing方法中就会提取在WebAsyncManager中注册的拦截器,组成拦截器链然后在异步任务的前后执行对应的回调方法
- • 而在WebAsyncManagerIntegrationFilter中注册的SecurityContextCallableProcessingInterceptor就会在这里面执行
4、SecurityContextCallableProcessingInterceptor
public final class SecurityContextCallableProcessingInterceptor extends CallableProcessingInterceptorAdapter {
private volatile SecurityContext securityContext;
public SecurityContextCallableProcessingInterceptor() {
}
public SecurityContextCallableProcessingInterceptor(SecurityContext securityContext) {
Assert.notNull(securityContext, "securityContext cannot be null");
setSecurityContext(securityContext);
}
/**
* 在执行异步任务之前执行,也就是还是用户线程的时候执行,是为了将安全上下文保存起来
* @param request
* @param task
* @param <T>
*/
@Override
public <T> void beforeConcurrentHandling(NativeWebRequest request, Callable<T> task) {
if (this.securityContext == null) {
setSecurityContext(SecurityContextHolder.getContext());
}
}
/**
* 在已经执行异步任务(submit)但是还没有执行Callable.call()方法,是为了将安全上下文保存到线程级别的安全上下文策略中
* @param request
* @param task
* @param <T>
*/
@Override
public <T> void preProcess(NativeWebRequest request, Callable<T> task) {
SecurityContextHolder.setContext(this.securityContext);
}
/**
* 异步任务已经执行完毕,是为了清空安全上下文
* @param request
* @param task
* @param concurrentResult
* @param <T>
*/
@Override
public <T> void postProcess(NativeWebRequest request, Callable<T> task, Object concurrentResult) {
SecurityContextHolder.clearContext();
}
private void setSecurityContext(SecurityContext securityContext) {
this.securityContext = securityContext;
}
}
- • 其原理很简单,当还在Tomcat线程的时候,将SecurityContext保存起来,然后进入异步线程后又取出来就行了
- • 而SecurityContext的存储策略有四种
image.png
- • 默认是ThreadLocalSecurityContextHolderStrategy,也就是将SecurityContext保存在Thread的threadLocals中