Java Future-Spring身份验证在AuditorAware中为空

Java Future-Spring身份验证在AuditorAware中为空,java,spring,mongodb,spring-security,completable-future,Java,Spring,Mongodb,Spring Security,Completable Future,这是我的设想: 我的应用程序已启用Mongo审核,并带有一个自定义AuditorAware,可从SecurityContext获取当前用户。这在同步方法中效果很好,并且成功保存了当前的auditor,但是我无法使它在@Async方法中正常工作 我有一个异步方法(CompletableFuture),可以对我的Mongo数据库进行一些更新。调用AuditorAware.getCurrentAuditor()时,不存在身份验证信息,并且我无法获取当前审计员(SecurityContextHolder

这是我的设想:

我的应用程序已启用Mongo审核,并带有一个自定义AuditorAware,可从
SecurityContext
获取当前用户。这在同步方法中效果很好,并且成功保存了当前的auditor,但是我无法使它在
@Async
方法中正常工作

我有一个异步方法(
CompletableFuture
),可以对我的Mongo数据库进行一些更新。调用
AuditorAware.getCurrentAuditor()
时,不存在身份验证信息,并且我无法获取当前审计员(
SecurityContextHolder.getContext().getAuthentication()
返回
null

我正在使用一个
DelegatingSecurityContextAsyncTaskExecutor

@Configuration
@EnableAsync
public class AsyncConfig implements AsyncConfigurer {

    @Override
    public Executor getAsyncExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(20);
        executor.setMaxPoolSize(100);
        executor.setQueueCapacity(200);
        executor.initialize();

        return new DelegatingSecurityContextAsyncTaskExecutor(executor);
    }

    @Override
    public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
        return new ItacaExceptionHandler();
    }

} 

如何使其正常工作?

Spring安全上下文始终绑定到Threadlocal

您可能需要为安全上下文另外设置MODE_INHERITABLETHREADLOCAL

@Bean
public MethodInvokingFactoryBean methodInvokingFactoryBean() {
    MethodInvokingFactoryBean methodInvokingFactoryBean = new MethodInvokingFactoryBean();
    methodInvokingFactoryBean.setTargetClass(SecurityContextHolder.class);
    methodInvokingFactoryBean.setTargetMethod("setStrategyName");
    methodInvokingFactoryBean.setArguments(new String[]{SecurityContextHolder.MODE_INHERITABLETHREADLOCAL});
    return methodInvokingFactoryBean;
}

在上的评论之后,您似乎没有正确地将
CompletableFuture
与Spring
@Async
一起使用

如果您使用启动任务,例如,它们将由执行,而不是您为
@Async
配置的任务。您可以使用将
执行器
作为参数的重载,但它实际上不会受益于
@Async
的优点

相反,您应该做的是让Spring处理任务执行,并简单地返回一个已完成的
可完成的未来
,如下所示:

@Async
public CompletableFuture<String> someMethod() {
    // do some computation, but return a completed future
    return CompletableFuture.completedFuture("Hello World!");
}
@Async
公共CompletableFuture-someMethod(){
//做一些计算,但返回一个完整的未来
返回CompletableFuture.completedFuture(“你好,世界!”);
}
Spring随后将在配置的执行器中异步执行您的方法,同时立即返回一个
CompletableFuture
,当您的方法返回时将完成该操作


如果您使用的是Spring 4.2或更高版本。否则需要一些实现,但这将是另一个问题。

根据,在使用重复使用线程的执行器时,使用
模式\u INHERITABLETHREADLOCAL
将不起作用(仅在创建线程时才会发生继承)。但是,它应该与
DelegatingSecurityContextAsyncTaskExecutor
一起使用@s1moner3d您确定您在问题中展示的遗嘱执行人确实被使用了吗
CompletableFuture
默认情况下使用公共ForkJoinPool。@DiDierrl如何检查?我确信它是在启动时实例化的time@DidierL我查过了,你完全正确!它使用
ForkJoinPool
。如何使用
DelegatingSecurityContextAsyncTaskExecutor
?@s1moner3d我想最简单的方法是调试
@Async
方法之一,查看它在哪个线程中运行,或者在该方法中打印
thread.getCurrentThread().getName()
。@s1moner3d这取决于如何创建
可完成的未来。大多数方法都有带有
Executor
参数的重载,但是如果您依赖于Spring
@Async
,我想您有一个工厂来处理它们的创建,所以应该在那里完成。
@Async
public CompletableFuture<String> someMethod() {
    // do some computation, but return a completed future
    return CompletableFuture.completedFuture("Hello World!");
}