How to get the current user in a Spring Security reactive (WebFlux) and non-reactive (MVC) application
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
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.
0 comments