3

I want to implement this example using Keyclock server with Spring Security 5.

I'm going to use OAuth2.0 authentication with JWT token. I'm interested how I can get the current logged in user into the Rest Endpoint?

I have configured Spring Security not to store user sessions using http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);.

One possible way is to use this code:

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
if (principal instanceof UserDetails) {
  String username = ((UserDetails)principal).getUsername();
} else {
  String username = principal.toString();
}

But I don't know is it going to work. Can someone give some advice for that case?

Peter Penzov
  • 1,126
  • 134
  • 430
  • 808

2 Answers2

1

SecurityContextHolder, SecurityContext and Authentication Objects

By default, the SecurityContextHolder uses a ThreadLocal to store these details, which means that the security context is always available to methods in the same thread of execution. Using a ThreadLocal in this way is quite safe if care is taken to clear the thread after the present principal’s request is processed. Of course, Spring Security takes care of this for you automatically so there is no need to worry about it.

SessionManagementConfigurer consist of isStateless() method which return true for stateless policy. Based on that http set the shared object with NullSecurityContextRepository and for request cache NullRequestCache. Hence no value will be available within HttpSessionSecurityContextRepository. So there might not be issue with invalid/wrong details for user with static method

Code:

        if (stateless) {
            http.setSharedObject(SecurityContextRepository.class,
                    new NullSecurityContextRepository());
        }

        if (stateless) {
            http.setSharedObject(RequestCache.class, new NullRequestCache());
        }

Code:

Method to get user details

    public static Optional<String> getCurrentUserLogin() {
        SecurityContext securityContext = SecurityContextHolder.getContext();
        return Optional.ofNullable(extractPrincipal(securityContext.getAuthentication()));
    }

    private static String extractPrincipal(Authentication authentication) {
        if (authentication == null) {
            return null;
        } else if (authentication.getPrincipal() instanceof UserDetails) {
            UserDetails springSecurityUser = (UserDetails) authentication.getPrincipal();
            return springSecurityUser.getUsername();
        } else if (authentication.getPrincipal() instanceof String) {
            return (String) authentication.getPrincipal();
        }
        return null;
    }


    public static Optional<Authentication> getAuthenticatedCurrentUser() {
        log.debug("Request to get authentication for current user");
        SecurityContext securityContext = SecurityContextHolder.getContext();
        return Optional.ofNullable(securityContext.getAuthentication());
    }

sessionManagement

.sessionManagement()
     .sessionCreationPolicy(SessionCreationPolicy.STATELESS)

You might like to explore Methods with Spring Security to get current user details with SessionCreationPolicy.STATELESS

Romil Patel
  • 12,879
  • 7
  • 47
  • 76
0

After the service validate the token, you can parse it, and put it into the securitycontext, it can contains various data, so you have to look after it what you need. For example, subject contains username etc...

SecurityContextHolder.getContext().setAuthentication(userAuthenticationObject);

The SecurityContextHolder's context maintain a ThreadLocal entry, so you can access it on the same thread as you write it in the question. Note that if you use reactive (webflux) methodology, then you have to put it into the reactive context instead.

zlaval
  • 1,941
  • 1
  • 10
  • 11