Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I access JWT claims in Spring API handler methods using Webflux?

I am adding a WebFilter to perform JWT authentication inside of SecurityWebFilterChain. We encode a lot of non-auth related information in the JWT that is needed by many of our API endpoints, so I need to be able to extract information out of the JWT and access that info in my API handler methods (eg, LoginController.java). What is the best pattern to achieve this?

Here is my SecurityWebFilterChain showing the WebFilter authentication:

    @Bean
    public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) {

        return http
                .authorizeExchange()
                .pathMatchers("/login", "/")
                .authenticated()
                .and()
                .addFilterAt(basicAuthenticationFilter(), SecurityWebFiltersOrder.HTTP_BASIC)
                .authorizeExchange()
                .pathMatchers("/adm")
                .authenticated()
                .and()
                .addFilterAt(basicAuthenticationFilter(), SecurityWebFiltersOrder.HTTP_BASIC)
                .authorizeExchange()
                .pathMatchers("/api/**")
                .access(authorizationManager)
                .and()
                .addFilterAt(bearerAuthenticationFilter(), SecurityWebFiltersOrder.AUTHENTICATION)
                .build();
    }

Here is where I would like to access the claims, in LoginController.java:

@RestController()
@RequestMapping(value = "/login")
public class LoginController {

    private final UserMongoRepository repository;

    @Autowired
    public LoginController(UserMongoRepository repository) {
        this.repository = repository;
    }

    @PostMapping("")
    public Mono<User> login(@RequestBody User post,
                            @RequestParam String user_id,
                            @RequestParam String username) {

        //Need to access information from JWT claims here

        return this.repository.findById(user_id);
    }
}
like image 543
AltJ Avatar asked Nov 07 '22 17:11

AltJ


1 Answers

I would create a customised Authentication object and store the required information inside it.

For the user-related data , store inside its Principal.For the non user-related data , sounds like Details is a good place to store.

Many built-in AuthenticationProvider will create a UserDetails and store to Principal. That means you can consider just create a customsied UserDetails if you are using those built-it AuthenticationProvider.

So depending on how you implement the authentication logic , you need to customise the related AuthenticationProvider or Filter etc. The aim is to access the HttpServletRequest , get JWT from the HTTP header , parse the JWT , setup and configure this customised Authentication object and set it to the SecurityContext :

SecurityContextHolder.getContext().setAuthentication(authenication);

To access this Authentication object in Controller , you can use :

Authentication auth = SecurityContextHolder.getContext().getAuthentication();
CurrentUser user = (CurrentUser) auth.getPrincipal();
CurrentRequestDetail detail= (CurrentRequestDetail) auth.getDetails();
/** CurrentUser and CurrentRequestDetail is the customised Principal and Details**/

If you need to access [Principal] only , you can use @AuthenticationPrincipal :

    @PostMapping("")
    public Mono<User> login(@RequestBody User post,
                            @RequestParam String user_id,
                            @RequestParam String username,
                            @AuthenticationPrincipal CurrentUser currentUser) {

        //Need to access information from JWT claims here

        return this.repository.findById(user_id);
    }
like image 50
Ken Chan Avatar answered Nov 14 '22 02:11

Ken Chan