Injecting Custom Principal to Controllers by Spring Security

I know this is an old question, but as it does come up on top on Google when searching for injecting a Principal, I'll post a 2020 update:

Since Spring Security 4.0 you can just simply inject an @AuthenticationPrincipal into your controller methods:

@RequestMapping(value = "/")
public ResponseEntity<List<Conversation>> listAfter(@AuthenticationPrincipal UserPrincipal user){
   // implementation
} 

This will work out of the box, no additional config required.


Fundamentally this seems like trouble integrating with Spring MVC and not a Spring Security issue. Spring Security has no way of knowing that Authentication@getPrinicpal() implements Principal since the API returns an Object.

I see a few options for you. Each has some pros and cons, but I think the best is using @ModelAttribute and @ControllerAdvice

@ModelAttribute and @ControllerAdvice

The easiest option is annotate a method with @ModelAttribute on custom @ControllerAdvice. You can find details in the Spring Reference.

@ControllerAdvice
public class SecurityControllerAdvice {

    @ModelAttribute
    public UserPrincipal customPrincipal(Authentication a) {
        return (UserPrincipal) a == null ? null : a.getPrincipal();
    }
}

Now in your controller you can do something like this:

@RequestMapping(value = "/")
public ResponseEntity<List<Conversation>> listAfter(@ModelAttribute UserPrincipal user){
   // implementation
}

Note that the @ModelAttribute is necessary only to ensure the @ModelAttribute is used over the HttpServletRequest#getPrincipal(). If it did not implement Principal, @ModelAttribute is not required.

@Value and ExpressionValueMethodArgumentResolver

You can also do something like this:

@RequestMapping(value = "/")
public ResponseEntity<List<Conversation>> listAfter(
  @Value("#{request.userPrincipal.principal}") UserPrincipal user){
   // implementation
}

This works because the HttpServletRequest is available as an attribute to the ExpressionValueMethodArgumentResolver (added by default by Spring MVC) which allows accessing things via SpEL. I find this less attractive than @ModelAttribute due to the constant that must be in the @Value annotation. It will be nicer when SPR-10760 is resolved which would allow for your own custom annotation to be used like:

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Value("#{request.userPrincipal.principal}")
public @interface CurrentUser { }

@Autowire RequestMappingHandlerAdapter

This is a bit sloppy because the RequestMappingHandlerAdapter has already been initialized, but you can change the ordering of the HandlerMethodArgumentResolvers as shown here:

@EnableWebMvc
@Configuration
public class WebMvcConfiguration 
  extends WebMvcConfigurerAdapter {
    ...
    @Autowired
    public void setArgumentResolvers(RequestMappingHandlerAdapter adapter) {
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
        resolvers.add(new CustomPrincipalArgumentResolver());
        resolvers.addAll(adapter.getArgumentResolvers().getResolvers());
        adapter.setArgumentResolvers(resolvers);
    }
}

Subclass WebMvcConfigurationSupport

You can also extend WebMvcConfigurationSupport instead of using @EnableWebMvc to ensure your HandlerMethodArgumentResolver is used first. For example:

@Configuration
public class WebConfiguration extends WebMvcConfigurationSupport {
    ...

    @Bean
    @Override
    public RequestMappingHandlerAdapter requestMappingHandlerAdapter() {
        RequestMappingHandlerAdapter adapter = super.requestMappingHandlerAdapter()();
        List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
        resolvers.add(new CustomPrincipalArgumentResolver());
        resolvers.addAll(adapter.getArgumentResolvers().getResolvers());
        adapter.setArgumentResolvers(resolvers);
        return adapter;
    }
}