Search code examples
javaspringapispring-securitythread-local

Accessing Spring Security Threadlocal user information from outside of spring security


I have multiple projects that need to pass user login information to common-api project that they call. The common-api does not have user credentials passed in via method calls, so I am hoping to make this information available via Threadlocal variables.

The first such project that needs to make this information available is a rest-web-service-api project that uses Spring Security, and sits on top of my common-api project.

I see that Spring Security stores the user information in a ThreadLocal variable... is there a way to access this from the common-api project without necessarily needing to know that Spring Security is who set it? I am quite unfamiliar with Spring Security and new to using Threadlocals so any help would be greatly appreciated.


Solution

  • Posting my own solution here in case it's useful down the road to someone else.

    Spring security (by default) does in fact store the user information in a Threadlocal variable, but the common-api will not have access to it unless it adds a spring-security dependency -if it does, the user information can be accessed (assuming you're executing in the same thread) using the following snippet:

    SecurityContext secureContext = SecurityContextHolder.getContext();
    Authentication auth = secureContext.getAuthentication();
    Object principal = auth.getPrincipal();
    
    String userName = null;
    if (principal instanceof UserDetails) {
        UserDetails userDetails = (UserDetails) principal;
        userName = userDetails.getUsername();
    } else {
        userName = principal.toString();
    }
    

    The solution I implemented was different however, because I did not want to introduce Spring Security to the common-api project, and I couldn't always rely on Spring Security being in the user of the API. So, I created a Singleton bean in the common-api that contains my own defined ThreadLocal variables that can be set from other projects and accessed from the common-api project (again, assuming they're running in the same thread).

    Code Snippet:

    public class CommonAPIThreadLocalStorageManager {
        private static CommonAPIThreadLocalStorageManager instance;
    
        // Typical singleton private constructor, static getInstance here
    
        private ThreadLocal<String> userID = new ThreadLocal<String>();
    
        public String getUserID() {
            return userID.get();
        }
    
        public void setUserID(String userID) {
            this.userID.set(userID);
        }