How to get active user's UserDetails
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:
- use an older version of Spring-Security,
- need to load your custom User Object from the Database by some information (like the login or id) stored in the principal or
- want to learn how a
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
public ModelAndView someRequestHandler(Principal principal) {
User activeUser = (User) ((Authentication) principal).getPrincipal();
...
}
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:
public ModelAndView someRequestHandler(@ActiveUser User activeUser) {
...
}
Therefore you only need to implement a WebArgumentResolver
. It has a method
Object resolveArgument(MethodParameter methodParameter,
NativeWebRequest webRequest)
throws Exception
That 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))
public class CurrentUserWebArgumentResolver implements WebArgumentResolver{
Object resolveArgument(MethodParameter methodParameter, NativeWebRequest webRequest) {
if(methodParameter is for type User && methodParameter is annotated with @ActiveUser) {
Principal principal = webRequest.getUserPrincipal();
return (User) ((Authentication) principal).getPrincipal();
} else {
return WebArgumentResolver.UNRESOLVED;
}
}
}
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.
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ActiveUser {}
In the configuration you only need to add this:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter"
id="applicationConversionService">
<property name="customArgumentResolver">
<bean class="CurrentUserWebArgumentResolver"/>
</property>
</bean>
@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+
public class CurrentUserHandlerMethodArgumentResolver
implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter methodParameter) {
return
methodParameter.getParameterAnnotation(ActiveUser.class) != null
&& methodParameter.getParameterType().equals(User.class);
}
@Override
public Object resolveArgument(MethodParameter methodParameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) throws Exception {
if (this.supportsParameter(methodParameter)) {
Principal principal = webRequest.getUserPrincipal();
return (User) ((Authentication) principal).getPrincipal();
} else {
return WebArgumentResolver.UNRESOLVED;
}
}
}
In the configuration, you need to add this
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="CurrentUserHandlerMethodArgumentResolver"/>
</mvc:argument-resolvers>
</mvc:annotation-driven>
@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 answer
It is just writing
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
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 within mvc: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
and AuthenticationPrincipalArgumentResolver
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
import org.springframework.security.core.annotation.AuthenticationPrincipal;
ModelAndView someRequestHandler(@AuthenticationPrincipal User activeUser) {
...
}
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 within mvc:argument-resolvers
- the same way I described it with may Spring 3.1 solution above.
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
@See Spring Security 5.0 Reference, Chapter 39.3 @AuthenticationPrincipal
Java Spring - Active Directory- How can I Get AD User Details (telNumber, full name, mail , address, description)?
You can set the a UserDetailsContextMapper
on your Provider
which allows custom strategy to be used for creating the UserDetails
that will be stored as the principal in the Authentication
.
provider.setUserDetailsContextMapper(new PersonContextMapper());
Then you can use the @AuthenticationPrincipal
annotation in your Controller to get the Person
(or a custom class) instance.
@GetMapping("/phone-number")
public String phoneNumber(@AuthenticationPrincipal Person person) {
return "Phone number: " + person.getTelephoneNumber();
}
You can find a full LDAP sample application provided by the Spring Security team.
GET UserDetails Authorities
You need to modify your getAuthoritiesEntities
private List<GrantedAuthority> getAuthoritiesEntities(Set<Role> userRoles) {
Set<GrantedAuthority> roles = new HashSet<>();
userRoles.forEach((role) -> {
roles.add(new SimpleGrantedAuthority(role.getRole()));
});
List<GrantedAuthority> grantedAuthorities = new ArrayList<>(roles);
return grantedAuthorities;
}
Now get roleList
List<AuthoritiesEntity>roleList=userEntity.getAuthoritiesEntities(userEntity.getRoles());
Now return authentication
return new org.springframework.security.core.userdetails.User(userEntity.getUsername(), userEntity.getPassword(), roleList);
Spring boot controller retrieve UserDetails
It seems like you are using jwt
, you don't need UserDetails
to compare it with.
change methods as :
public Boolean validateToken(String token) {
final String username = extractEmail(token);
return (!StringUtils.isEmpty(username) && !isTokenExpired(token));
}
@GetMapping("/validateToken")
public String validateToken(@RequestHeader(value="token") String token) {
if(jwtUtil.validateToken(token)) {
}
}
If your token is invalid you will not get exception in
extractEmail
method and if it is expired then methodisTokenExpired
will returnfalse
.
How to find out the currently logged-in user in Spring Boot?
As per request:
Spring Boot which uses Spring Security internally provides a SecurityContextHolder class which allows the lookup of the currently authenticated user via:
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
The authentication instance now provides the following methods:
- Get the username of the logged in user:
getPrincipal()
- Get the password of the authenticated user:
getCredentials()
- Get the assigned roles of the authenticated user:
getAuthorities()
- Get further details of the authenticated user:
getDetails()
Related Topics
String.Replaceall(Regex) Makes the Same Replacement Twice
How to Check If a Single Character Appears in a String
Java: Ternary with No Return. (For Method Calling)
Why Would One Mark Local Variables and Method Parameters as "Final" in Java
How to Create an .Exe for a Java Program
Spring Boot CSS Showing Up Blank/Not Loading After Trying Everything
How to Get a Unique Computer Identifier in Java (Like Disk Id or Motherboard Id)
Java: Error: Variable Might Not Have Been Initialized
Creating Multiple Log Files of Different Content with Log4J
How to Set Output Stream to Textarea
Easiest Way to Merge a Release into One Jar File
Why Doesn't Java Support Unsigned Ints
Setting Background Color for a Jframe
Split String on Spaces in Java, Except If Between Quotes (I.E. Treat \"Hello World\" as One Token)
What Should I Set Java_Home Environment Variable on MACos X 10.6