我可以在发出访问令牌时包含用户信息吗?

Rut*_*ulV 26 spring spring-security spring-security-oauth2

我在一些oauth2实现中看到了授权服务器在发出访问令牌时返回的响应的附加信息.我想知道是否有办法使用spring-security-oauth2来实现这一目标.我希望能够在访问令牌响应中包含一些用户权限,以便我的消费应用程序不需要管理用户权限,但仍然可以将用户设置在他们自己的安全上下文中并应用他们自己的任何spring-security检查.

  1. 我如何获得有关访问令牌响应的信息?
  2. 我如何拦截oauth2客户端上的信息并将其设置在安全上下文中?

我想另一种选择是使用JWT令牌并与客户端应用程序共享适当的信息,以便他们可以解析令牌中的用户/权限并将其设置在上下文中.这让我更加不舒服,因为我更愿意控制哪些客户端应用程序可以访问此信息(仅限受信任的应用程序),而AFAIK只有授权服务器和资源服务器应该知道如何解析JWT令牌.

Phi*_*ppe 52

您将需要实现自定义TokenEnhancer,如下所示:

public class CustomTokenEnhancer implements TokenEnhancer {

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        User user = (User) authentication.getPrincipal();
        final Map<String, Object> additionalInfo = new HashMap<>();

        additionalInfo.put("customInfo", "some_stuff_here");
        additionalInfo.put("authorities", user.getAuthorities());

        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);

        return accessToken;
    }

}
Run Code Online (Sandbox Code Playgroud)

并将其作为具有相应setter的bean添加到AuthorizationServerConfigurerAdapter

@Configuration
@EnableAuthorizationServer
protected static class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter {

    // Some autowired stuff here

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // @formatter:off
        endpoints
            // ...
            .tokenEnhancer(tokenEnhancer());
        // @formatter:on
    }

    @Bean
    @Primary
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        // ...
        tokenServices.setTokenEnhancer(tokenEnhancer());
        return tokenServices;
    }

    // Some @Bean here like tokenStore

    @Bean
    public TokenEnhancer tokenEnhancer() {
        return new CustomTokenEnhancer();
    }

}
Run Code Online (Sandbox Code Playgroud)

然后在控制器中(例如)

@RestController
public class MyController {

    @Autowired
    private AuthorizationServerTokenServices tokenServices;

    @RequestMapping(value = "/getSomething", method = RequestMethod.GET)
    public String getSection(OAuth2Authentication authentication) {
        Map<String, Object> additionalInfo = tokenServices.getAccessToken(authentication).getAdditionalInformation();

        String customInfo = (String) additionalInfo.get("customInfo");
        Collection<? extends GrantedAuthority> authorities = (Collection<? extends GrantedAuthority>) additionalInfo.get("authorities");

        // Play with authorities

        return customInfo;
    }

}
Run Code Online (Sandbox Code Playgroud)

我个人使用JDBC TokenStore所以我的"一些自动装配的东西在这里"对应于一些@Autowired Datasource,PasswordEncoder和什么不对.

希望这有帮助!

  • 只是提一下:这对JwtTokenStore不起作用.在Spring Boot 1.4.x中,`public OAuth2AccessToken getAccessToken(OAuth2Authentication authentication)`方法被硬编码为返回null. (4认同)

jch*_*brt 20

如果您正在使用Spring,JwtAccessTokenConverter或者DefaultAccessTokenConverter您可以添加自定义CustomTokenEnhancer(请参阅第一个响应)并使用TokenEnhancerChain应用它,如下所示:

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

    TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
    enhancerChain.setTokenEnhancers(Arrays.asList(customTokenEnhancer(), accessTokenConverter()));

    endpoints.tokenStore(tokenStore())
            .tokenEnhancer(enhancerChain)
            .authenticationManager(authenticationManager);
}

@Bean
protected JwtAccessTokenConverter jwtTokenEnhancer() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey("my_signing_key");
    return converter;
}

@Bean public TokenEnhancer customTokenEnhancer() {
    return new CustomTokenEnhancer();
}
Run Code Online (Sandbox Code Playgroud)

另一个解决方案是创建一个自定义TokenConverter,它扩展Spring JwtAccessTokenConverter并使用您的自定义声明覆盖enhance ()方法.

public class CustomTokenConverter extends JwtAccessTokenConverter {

@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {

    final Map<String, Object> additionalInfo = new HashMap<>();
    additionalInfo.put("customized", "true");
    User user = (User) authentication.getPrincipal();
    additionalInfo.put("isAdmin", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList()).contains("BASF_ADMIN"));
    ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);

    return super.enhance(accessToken, authentication);
    }
} 
Run Code Online (Sandbox Code Playgroud)

然后:

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {

    endpoints.tokenStore(tokenStore())
            .tokenEnhancer(customTokenEnhancer())
            .authenticationManager(authenticationManager);
}

@Bean public CustomTokenConverter customTokenEnhancer() {
    return new CustomTokenConverter();
}
Run Code Online (Sandbox Code Playgroud)