When developing an application, we sometimes need to access the currently logged in user programmatically. In this post, we’ll discuss how to do that when using Spring Security — both in non-reactive (Spring MVC) as well as reactive (Spring WebFlux) applications.

The code snippets are derived from the Spring Lemon library. If you haven’t heard of Spring Lemon, it’s a library encapsulating the sophisticated non-functional code and configuration that’s needed when developing reactive and non-reactive real-world RESTful web services using the Spring framework and Spring Boot.

When someone logs in, Spring Security creates an Authentication object. The authentication object has a principal property, which stores the current user.

So, if you can access the Authentication object, you can get the current user, like this:

public static Optional<User> currentUser(Authentication auth) {
    if (auth != null) {
        Object principal = auth.getPrincipal();
        if (principal instanceof User) // User is your user type that implements UserDetails
            return Optional.of((User) principal);
    }
    return Optional.empty();
}

But, how to get access to the Authentication object?

The authentication object is stored in the SecurityContext object. Given the SecurityContext, a reference to the authentication object can be obtained just as below:

Authentication auth = securityContext.getAuthentication();

How to get access to the SecurityContext becomes the question then. It's different for reactive and non-reactive applications.

Accessing SecurityContext in a non-reactive (Spring MVC) application

Traditional (non-reactive) Spring Security provides a static method to access the security context, which can be called from anywhere, as below

SecurityContext context = SecurityContextHolder.getContext();

Accessing SecurityContext in a reactive (Spring WebFlux) application

Reactive Spring Security provides that in a reactive manner, as below:
Mono<SecurityContext> context = ReactiveSecurityContextHolder.getContext();

Beware that Mono<SecurityContext> returned above is just the assembly that gets resolved later at subscription time. Here is an example usage:

@PostMapping("/current-user")
public Mono<UserDto<ID>> getCurrentUser(ServerWebExchange exchange) {
    return ReactiveSecurityContextHolder.getContext()
            .map(SecurityContext::getAuthentication)
            .map(Authentication::getPrincipal)
            .map(MyPrincipal::currentUser)
            .zipWith(exchange.getFormData())
            .doOnNext(tuple -> {                    
                // based on some input parameters, amend the current user data to be returned
            })
            .map(Tuple2::getT1);
}

For exact details, refer to LecUtils, LemonUtils and LerUrils of Spring Lemon.