Reputation: 923
I'm trying to convert a sequential series of calls of spring service to be asynchronous.
I have annotated the method with @Async
and added taskExecutor configuratinos.
I can see that the method is now being invoked asynchronously but I'm having issues with SecurityContextHolder.getContext()
throwing this error:
java.util.concurrent.ExecutionException: java.lang.NullPointerException
Would really appreciate any insights. Thanks!
Upvotes: 2
Views: 3585
Reputation: 21
If you want to access the security context in the asynchronous calls, You could implement the context aware thread pool executor to store the security context when creating threads like below.
public class CustomExecutor extends ThreadPoolTaskExecutor {
@Override
public <T> Future<T> submit(Callable<T> task) {
return super.submit(new ScopeAwareCallable<T>(task, SecurityContextHolder.getContext()));
}
public class ScopeAwareCallable<T> implements Callable<T> {
private Callable<T> callableTask;
private SecurityContext securityContext;
public ScopeAwareCallable(Callable<T> task, SecurityContext secContex) {
this.callableTask = task;
this.securityContext = secContex;
}
@Override
public T call() throws Exception {
if(securityContext != null){
SecurityContextHolder.setContext(securityContext);
}
try {
return callableTask.call();
}
finally {
SecurityContextHolder.clearContext();
}
}
}
configure this as your task executor in the spring configuration. If you're using the Runnable instead of Callable, then override other methods in ThreadPoolTaskExecutor which supports the Runnable execution as well.
Upvotes: 0
Reputation: 1520
Since Spring-Security 3.2 there is a nice annotation @AuthenticationPrincipal
described at the end of this answer. This is the best way to go when you use Spring-Security >= 3.2. You can inject it in various ways. For more information look at this answer
Upvotes: 0
Reputation: 923
I found a solution, changing the startegy to "MODE_INHERITABLETHREADLOCA" solved my problem.
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetClass" value="org.springframework.security.core.context.SecurityContextHolder"/>
<property name="targetMethod" value="setStrategyName"/>
<property name="arguments">
<list>
<value>MODE_INHERITABLETHREADLOCAL</value>
</list>
</property>
</bean>
Upvotes: 3
Reputation: 3854
The SecurityContext is stored in a ThreadLocal. So if you access it from a new thread that didn't set it anywhere, then the SecurityContext is null.
Update: Added Threadlocal javadoc link
Upvotes: 7