In my controllers, when I need the active (logged in) user, I am doing the following to get my UserDetails
implementation:
User activeUser = (User)SecurityContextHolder.getContext().getAuthentication().getPrincipal();
log.debug(activeUser.getSomeCustomField());
It works fine, but I would think Spring could make life easier in a case like this. Is there a way to have the UserDetails
autowired into either the controller or the method?
For example, something like:
public ModelAndView someRequestHandler(Principal principal) { ... }
But instead of getting the UsernamePasswordAuthenticationToken
, I get a UserDetails
instead?
I'm looking for an elegant solution. Any ideas?
Best Answer
Preamble: Since Spring-Security 3.2 there is a nice annotation
@AuthenticationPrincipal
described at the end of this answer. This is the best way to go when you use Spring-Security >= 3.2.When you:
HandlerMethodArgumentResolver
orWebArgumentResolver
can solve this in an elegant way, or just want to an learn the background behind@AuthenticationPrincipal
andAuthenticationPrincipalArgumentResolver
(because it is based on aHandlerMethodArgumentResolver
)then keep on reading — else just use
@AuthenticationPrincipal
and thank to Rob Winch (Author of@AuthenticationPrincipal
) and Lukas Schmelzeisen (for his answer).(BTW: My answer is a bit older (January 2012), so it was Lukas Schmelzeisen that come up as the first one with the
@AuthenticationPrincipal
annotation solution base on Spring Security 3.2.)Then you can use in your controller
That is ok if you need it once. But if you need it several times its ugly because it pollutes your controller with infrastructure details, that normally should be hidden by the framework.
So what you may really want is to have a controller like this:
Therefore you only need to implement a
WebArgumentResolver
. It has a methodThat gets the web request (second parameter) and must return the
User
if its feels responsible for the method argument (the first parameter).Since Spring 3.1 there is a new concept called
HandlerMethodArgumentResolver
. If you use Spring 3.1+ then you should use it. (It is described in the next section of this answer))You need to define the Custom Annotation -- You can skip it if every instance of User should always be taken from the security context, but is never a command object.
In the configuration you only need to add this:
@See: Learn to customize Spring MVC @Controller method arguments
It should be noted that if you're using Spring 3.1, they recommend HandlerMethodArgumentResolver over WebArgumentResolver. - see comment by Jay
The same with
HandlerMethodArgumentResolver
for Spring 3.1+In the configuration, you need to add this
@See Leveraging the Spring MVC 3.1 HandlerMethodArgumentResolver interface
Spring-Security 3.2 Solution
Spring Security 3.2 (do not confuse with Spring 3.2) has own build in solution:
@AuthenticationPrincipal
(org.springframework.security.web.bind.annotation.AuthenticationPrincipal
) . This is nicely described in Lukas Schmelzeisen`s answerIt is just writing
To get this working you need to register the
AuthenticationPrincipalArgumentResolver
(org.springframework.security.web.bind.support.AuthenticationPrincipalArgumentResolver
) : either by "activating"@EnableWebMvcSecurity
or by registering this bean withinmvc:argument-resolvers
- the same way I described it with may Spring 3.1 solution above.@See Spring Security 3.2 Reference, Chapter 11.2. @AuthenticationPrincipal
Spring-Security 4.0 Solution
It works like the Spring 3.2 solution, but in Spring 4.0 the
@AuthenticationPrincipal
andAuthenticationPrincipalArgumentResolver
was "moved" to an other package:org.springframework.security.core.annotation.AuthenticationPrincipal
org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver
(But the old classes in its old packges still exists, so do not mix them!)
It is just writing
To get this working you need to register the (
org.springframework.security.web.method.annotation.
)AuthenticationPrincipalArgumentResolver
: either by "activating"@EnableWebMvcSecurity
or by registering this bean withinmvc:argument-resolvers
- the same way I described it with may Spring 3.1 solution above.@See Spring Security 5.0 Reference, Chapter 39.3 @AuthenticationPrincipal