2016-05-13 65 views
1

我想從Spring上下文的用戶在應用程序春天如下:獲得用戶

Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 

的問題是,這些方法是異步的,與註解@Async:

@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。用戶傳播到異步方法,但如果我註銷,異步方法中的用戶爲空。這是我的代碼:

@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(); 
    } 
} 

我也用一個ThreadPoolTask​​Executor類和設置安全春用「MODE_INHERITABLETHREADLOCAL」的背景。但結果是一樣的。如果我登錄到應用程序,用戶不爲空。如果我沒有記錄該用戶爲空。我真的希望運行該方法的用戶,而不是當前用戶登錄。我的代碼:

@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; 
    } 
} 

最後,我發現這個職位Spring Security and @Async。我嘗試使用CustomThreadPoolTask​​Executor重寫exe​​cute方法。但是這個方法永遠不會運行運行ThreadPoolTask​​Executor類的方法是:

<T> Future<T> submit(Callable<T> task) 

我的代碼:

@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(); 
       } 
      } 
     }); 
    } 
} 

我定製的執行方法永遠不會運行。 我在自定義ThreadPoolTask​​Executor中做錯了什麼?獲取運行異步方法的用戶的其他方法。沒有上下文的當前用戶。

回答

0

也許這有助於獲得所謂的執行法(在我的情況下工作):

@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 new DelegatingSecurityContextAsyncTaskExecutor(executor); 
} 
+0

在我的問題我用DelegatingSecurityContextAsyncTaskExecutor了。謝謝你的回答。我的最終解決方案是將用戶作爲參數傳遞。 – oscar