如何将 OAuth 2 令牌映射到资源服务器中的 UserDetails 对象?
How do I map OAuth 2 token to UserDetails object in a resource server?
我有 2 个独立的 Spring 引导应用程序,一个用作 OAuth 2 授权服务器,另一个用作资源服务器。我在我的资源服务器中使用 Spring 的 RemoteTokenServices
来检查来自授权服务器的令牌。现在,我试图在我的资源服务器应用程序中定义受保护的控制器代码,但我不确定如何将 UserDetails
class 映射到通过 OAuth 2 机制提供的身份验证主体。
我已经使用自定义 TokenEnhancer
设置了我的授权服务器,它向令牌添加了更多详细信息,以便 /oauth/check_token?token=<token>
returns 具有自定义字段,我想将其映射到我的资源服务器控制器。
在授权服务器也是资源服务器的更单一的设置中,我可以这样定义使用经过身份验证的主体的控制器方法:
//User implements UserDetails
public Map<String, Object> getResource(@AuthenticationPrincipal User user) {
//code that uses the user object
}
但是,这在更分布式的方法中似乎并不那么直接。映射失败,user
参数最终成为空对象。我尝试使用以下方法:
public Map<String, Object> getResource(Authentication authentication) {
//code that uses the authentication object
}
虽然上面的代码成功映射了身份验证详细信息,但它并没有为我提供直接访问我通过前面提到的 TokenEnhancer
设置的自定义字段的方法。我似乎无法从 Spring 文档中找到与此相关的任何内容。
您是否启用了 AuthenticationPrincipalArgumentResolver
,就像关注 xml 一样?
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
并且你需要实现UserDetails
到return你自己的CustomerUser object
,然后你可以使用注释直接获取主体。
为了解决这个问题,让我先了解一下架构背景。通过@AuthenticationPrincipal
自动映射的UserDetails
对象来自活动Authentication
对象的principal
字段。资源服务器控制器可以访问 OAuth2Authencation
对象,它是 Spring OAuth2 安全框架的 Authentication
的专用实例,只需将其声明为方法参数的一部分即可。
public void controllerMethod(OAuth2Authentication authentication) {
//controller definition
}
知道了这一点,现在的问题就转移到如何确保Authentication
对象中的getPrincipal()
方法是我自定义的UserDetails
class的一个实例了。我在资源服务器应用程序中使用的 RemoteTokenServices
使用 AccessTokenConverter
的实例来解释授权服务器发送的令牌详细信息。默认情况下,它使用 DefaultAccessTokenConverter
,它只是将身份验证主体设置为用户名,即 String
。该转换器利用 UserAuthenticationConverter
将来自授权服务器的数据转换为 Authentication
的实例。这是我需要定制的:
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);
完成所有这些设置后,@AuthenticationPrincipal
机制现在可以正常工作了。
我有 2 个独立的 Spring 引导应用程序,一个用作 OAuth 2 授权服务器,另一个用作资源服务器。我在我的资源服务器中使用 Spring 的 RemoteTokenServices
来检查来自授权服务器的令牌。现在,我试图在我的资源服务器应用程序中定义受保护的控制器代码,但我不确定如何将 UserDetails
class 映射到通过 OAuth 2 机制提供的身份验证主体。
我已经使用自定义 TokenEnhancer
设置了我的授权服务器,它向令牌添加了更多详细信息,以便 /oauth/check_token?token=<token>
returns 具有自定义字段,我想将其映射到我的资源服务器控制器。
在授权服务器也是资源服务器的更单一的设置中,我可以这样定义使用经过身份验证的主体的控制器方法:
//User implements UserDetails
public Map<String, Object> getResource(@AuthenticationPrincipal User user) {
//code that uses the user object
}
但是,这在更分布式的方法中似乎并不那么直接。映射失败,user
参数最终成为空对象。我尝试使用以下方法:
public Map<String, Object> getResource(Authentication authentication) {
//code that uses the authentication object
}
虽然上面的代码成功映射了身份验证详细信息,但它并没有为我提供直接访问我通过前面提到的 TokenEnhancer
设置的自定义字段的方法。我似乎无法从 Spring 文档中找到与此相关的任何内容。
您是否启用了 AuthenticationPrincipalArgumentResolver
,就像关注 xml 一样?
<mvc:annotation-driven>
<mvc:argument-resolvers>
<bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
</mvc:argument-resolvers>
</mvc:annotation-driven>
并且你需要实现UserDetails
到return你自己的CustomerUser object
,然后你可以使用注释直接获取主体。
为了解决这个问题,让我先了解一下架构背景。通过@AuthenticationPrincipal
自动映射的UserDetails
对象来自活动Authentication
对象的principal
字段。资源服务器控制器可以访问 OAuth2Authencation
对象,它是 Spring OAuth2 安全框架的 Authentication
的专用实例,只需将其声明为方法参数的一部分即可。
public void controllerMethod(OAuth2Authentication authentication) {
//controller definition
}
知道了这一点,现在的问题就转移到如何确保Authentication
对象中的getPrincipal()
方法是我自定义的UserDetails
class的一个实例了。我在资源服务器应用程序中使用的 RemoteTokenServices
使用 AccessTokenConverter
的实例来解释授权服务器发送的令牌详细信息。默认情况下,它使用 DefaultAccessTokenConverter
,它只是将身份验证主体设置为用户名,即 String
。该转换器利用 UserAuthenticationConverter
将来自授权服务器的数据转换为 Authentication
的实例。这是我需要定制的:
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);
完成所有这些设置后,@AuthenticationPrincipal
机制现在可以正常工作了。