Is SecurityContextHolder thread safe?
I use SecurityContextHolder
and a custom UserDetailsService
to obtain Use开发者_开发技巧rDetails
from SecurityContextHolder
:
Object o = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
UserDetailsDTO user = (UserDetailsDTO) o;
I left out the null checks, etc., but that's the idea. I'm using this in an @Around
pointcut of an @Aspect
:
@Around("execution(* user.service.*.*(..))")
public Object audit(ProceedingJoinPoint call) throws Throwable {
// get user id
// add audit row in db
}
Looking at the SecurityContextHolder
class, it uses a ThreadLocal
by default, but the pointcut stuff also seems to have some sort of encapsulated threading logic.
Is it possible that there could be user collision (i.e. access UserA from one session for a UserB audit event in another concurrent session), or possibly a null user altogether.
Is there a better way to obtain the credentials/user profile?
Yes, it's thread safe with the default strategy (MODE_THREADLOCAL
) (as long as you don't try to change the strategy on the fly). However, if you want spawned threads to inherit SecurityContext
of the parent thread, you should set MODE_INHERITABLETHREADLOCAL
.
Also aspects don't have any "threading logic", they are executed at the same thread as the adviced method.
in general, ThreadLocal will not be friendly in a global cached thread pool. An ExecutorService's default cached thread pool (Executors.newCachedThreadPool()) will have either the initializing thread's ThreadLocal storage, or an empty one. In this situation, setting MODE_INHERITABLETHREADLOCAL will not change anything, unless the cached threadpool is initialized per request, which would be a pretty bad usage of it.. Make sure any underlying frameworks or libraries are not using the Executors.newCachedThreadPool() to provide thread pooling for you.
Yes it is thread safe . You should just be calling SecurityContextHolder.getContext().getAuthentication().getName()
精彩评论