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.