如何将OAuth 2令牌映射到资源服务器中的UserDetails对象?

时间:2016-12-11 12:31:12

标签: java spring spring-mvc spring-boot spring-oauth2

我有两个独立的Spring Boot应用程序,一个用作OAuth 2授权服务器,另一个用作资源服务器。我在资源服务器中使用Spring的RemoteTokenServices来检查授权服务器中的令牌。现在,我正在尝试在资源服务器应用程序中定义受保护的控制器代码,但我不确定如何将UserDetails类映射到通过OAuth 2机制提供的身份验证主体。

我已经使用自定义TokenEnhancer设置了我的授权服务器,该服务器会向令牌添加更多详细信息,以便/oauth/check_token?token=<token>返回自定义字段,我想将其映射到资源服务器控制器。

在一个更加单一的设置中,授权服务器也是资源服务器,我可以定义以这种方式使用经过身份验证的主体的控制器方法:

//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文档中找到任何关于此的内容。

2 个答案:

答案 0 :(得分:18)

要解决此问题,请先介绍一下建筑背景。通过UserDetails自动映射的@AuthenticationPrincipal对象来自活动principal对象的Authentication字段。资源服务器控制器可以访问OAuth2Authencation对象,该对象是Spring OAuth2安全框架的Authentication的专用实例,只需将其声明为方法参数的一部分即可。

public void controllerMethod(OAuth2Authentication authentication) {
    //controller definition
}

了解这一点,问题现在转移到如何确保getPrincipal()对象中的Authentication方法是我的自定义UserDetails类的实例。我在资源服务器应用程序中使用的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机制现在可以按预期工作。

答案 1 :(得分:0)

您是否启用了AuthenticationPrincipalArgumentResolver,如下面的xml?

<mvc:annotation-driven>
        <mvc:argument-resolvers>
                <bean class="org.springframework.security.web.method.annotation.AuthenticationPrincipalArgumentResolver" />
        </mvc:argument-resolvers>
</mvc:annotation-driven>

您需要实现UserDetails以返回自己的CustomerUser object,然后您可以使用注释直接获取主体。