Как получать пользователь, который выполняет асинхронный метод?

Я пробую получать пользователь контекста, который выполняет асинхронный метод в проекте со Спринг и Спринг security следующей формы:

@Service
    @Transactional
    public class FooServiceImpl implements FooService {

        @Async("asyncExecutor")
        public void fooMethod(String bar) {
            System.out.println("Foo: " + bar);
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        }
    }

Результат недействительный, так как контекст не распространяется в асинхронные методы, которые работают в другом трэде. Я это решил используя один SecurityContextDelegationAsyncTaskExecutor. С этим распространяется пользователь logueado в асинхронный метод. Проблема - что, если я deslogueo приложения пользователь недействительный. То, что я хочу, так это пользователь, который выполняет метод и не настоящего.

Мой код:

@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {

    @Override
    @Bean(name = "asyncExecutor")
    public Executor getAsyncExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        executor.setMaxPoolSize(1);
        executor.setThreadGroupName("MyCustomExecutor");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setBeanName("asyncExecutor");
        executor.initialize();

        return new DelegatingSecurityContextAsyncTaskExecutor(executor);
    }

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

Также я попытался конфигурировать Контекст spring с выбором MODE_INHERITABLETHREADLOCAL. То, что он делает, состоит в том, чтобы пропагандировать контекст между трэдами; но у меня есть та же проблема. В desloguearse, пользователь в асинхронном методе недействительный. Код:

@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {

    @Override
    @Bean(name = "asyncExecutor")
    public Executor getAsyncExecutor() {

        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();

        executor.setMaxPoolSize(1);
        executor.setThreadGroupName("MyCustomExecutor");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setBeanName("asyncExecutor");
        executor.initialize();

        return executor;
    }

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

}

@Configuration
@ComponentScan(basePackageClasses = Application.class, includeFilters = @Filter({Controller.class}), useDefaultFilters = true)
public class MvcConfiguration extends WebMvcConfigurationSupport {

    //others beans

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

В конце концов, я осуществил один ThreadPoolTaskExecutor sobreescribiendo метод execute, для того, чтобы он создал новый контекст и это скопировал. Проблема состоит в том, что мой метод execute не работает; вместо этого метода работает submit ThreadPoolTaskExecutor. Осуществление:

@Configuration
@EnableAsync
public class SpringAsyncConfig implements AsyncConfigurer {

    @Override
    @Bean(name = "asyncExecutor")
    public Executor getAsyncExecutor() {

        CustomThreadPoolTaskExecutor executor = new CustomThreadPoolTaskExecutor();

        executor.setMaxPoolSize(1);
        executor.setThreadGroupName("MyCustomExecutor");
        executor.setWaitForTasksToCompleteOnShutdown(true);
        executor.setBeanName("asyncExecutor");
        executor.initialize();

        return executor;
    }

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

}

public class CustomThreadPoolTaskExecutor extends ThreadPoolTaskExecutor {

    private static final long serialVersionUID = 1L;

    @Override
    public void execute(final Runnable r) {
        final Authentication a = SecurityContextHolder.getContext().getAuthentication();

        super.execute(new Runnable() {
            @Override
            public void run() {
                try {
                    SecurityContext ctx = SecurityContextHolder.createEmptyContext();
                    ctx.setAuthentication(a);
                    SecurityContextHolder.setContext(ctx);
                    r.run();
                } finally {
                    SecurityContextHolder.clearContext();
                }
            }
        });
    }
}

Что я врежу? Какой-то способ хранить и возвращать пользователь, который выполняет асинхронный метод?

29
задан 20.04.2017, 10:47
0 ответов