Use @AuthenticationPrincipal with JwtAuthenticationToken to use own user class

Wim Deblauwe :

I am using Spring Boot 2.2.5 with Spring Security 5.2.2 using spring-security-oauth2-resource-server and spring-security-oauth2-jose dependencies.

In my controller methods, I have this working:

@GetMapping
public ResponseEntity<?> doSomething(@AuthenticationPrincipal JwtAuthenticationToken principal) {
    User user = getUser(principal);
    ...
}

The principal gets injected and contains the id of the user on Azure (I am using Azure AD B2C).

The first thing I need to do in every method is get my own User object using this private method that retrieves the User from my userService Spring bean:

    private User getUser(JwtAuthenticationToken principal) {
        AuthorizationServerUserId authorizationServerUserId = AuthorizationServerUserId.fromPrincipal(principal);
        return userService.findByAuthorizationServerUserId(authorizationServerUserId)
                          .orElseThrow(() -> UserNotFoundException.forAuthorizationServerUserId(authorizationServerUserId));
    }

How can I configure Spring (Boot) so that this works:

@GetMapping
public ResponseEntity<?> doSomething(@AuthenticationPrincipal User user) {

}

The security configuration is currently done like this:

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .oauth2ResourceServer(OAuth2ResourceServerConfigurer::jwt)
                .authorizeRequests(registry -> {
                    registry.antMatchers("/registration/**").permitAll();

                    registry.antMatchers("/api/**").authenticated();
                });
    }
}
Eleftheria Stein-Kousathana :

@AuthenticationPrincipal accepts a SpEL expression as a parameter.

You can specify the bean and method that transforms the principal into a User in the provided SpEL expression.

@GetMapping
public ResponseEntity<?> doSomething(@AuthenticationPrincipal(expression = "@userService.getUser(#this)") User user) {

}

where userService refers to the UserService bean.

You can take it one step further by creating a custom annotation that uses @AuthenticationPrincipal as a meta annotation.

@Target({ElementType.PARAMETER, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@AuthenticationPrincipal(expression = "@userService.getUser(#this)")
public @interface CurrentUser {}

Then your controller would become

@GetMapping
public ResponseEntity<?> doSomething(@CurrentUser User user) {

}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=301158&siteId=1