I have 2 separate Spring Boot applications, one serving as an an OAuth 2 authorization server, and the other as resource server. I\'m using Spring\'s RemoteTokenServices
To resolve the issue, let me go through a bit of architectural background first. The UserDetails
object automatically mapped through the @AuthenticationPrincipal
comes from the principal
field of the active Authentication
object. A resource server controller has access to an OAuth2Authencation
object, which is a specialized instance of Authentication
for Spring OAuth2 security framework, just by simply declaring it as part of the method parameters.
public void controllerMethod(OAuth2Authentication authentication) {
//controller definition
}
Knowing this, the problem now shifts to how to make sure that the getPrincipal()
method in the Authentication
object is an instance of my custom UserDetails
class. The RemoteTokenServices
I use in the resource server application uses an instance of AccessTokenConverter
to interpret token details sent by the authorization server. By default, it uses DefaultAccessTokenConverter
, which just sets the authentication principal as the username, which is a String
. This converter makes use of UserAuthenticationConverter
to convert the data coming from the authorization server into an instance of Authentication
. This is what I needed to customize:
DefaultAccessTokenConverter tokenConverter = new DefaultAccessTokenConverter();
tokenConverter.setUserTokenConverter(new DefaultUserAuthenticationConverter() {
@Override
public Authentication extractAuthentication(Map<String, ?> map) {
Authentication authentication = super.extractAuthentication(map);
// User is my custom UserDetails class
User user = new User();
user.setSpecialKey(map.get("specialKey").toString());
return new UsernamePasswordAuthenticationToken(user,
authentication.getCredentials(), authentication.getAuthorities());
}
});
tokenServices.setAccessTokenConverter(tokenConverter);
With all these set up, the @AuthenticationPrincipal
mechanism now works as expected.
Did you enable the AuthenticationPrincipalArgumentResolver
, like following xml?
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
And you need to implement the UserDetails
to return your own CustomerUser object
, then you can use the annotation to get principal directly.