Как настроить ресурсный сервер в Spring Security для использования дополнительной информации в токере JWT

У меня есть маркер toauth2 jwt token, настроенный для установки дополнительной информации об пользовательских полномочиях.

@Configuration
@Component
public class CustomTokenEnhancer extends JwtAccessTokenConverter {

    CustomTokenEnhancer(){
        super();
    }

    @Override
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
        // TODO Auto-generated method stub
        MyUserDetails user = (MyUserDetails) authentication.getPrincipal();
        final Map<String, Object> additionalInfo = new HashMap<>();
        @SuppressWarnings("unchecked")
        List<GrantedAuthority> authorities= (List<GrantedAuthority>) user.getAuthorities();
        additionalInfo.put("authorities", authorities);

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

        return accessToken;
    }

}

Я не уверен, как настроить мой сервер ресурсов для извлечения полномочий пользователя, установленных сервером oauth2, и использовать этот авторитет, который будет использоваться для @Secured аннотированных контроллеров в Spring Security framework.

Конфигурация моего сервера Auth выглядит так:

@Configuration
@EnableAuthorizationServer
public class OAuth2Config extends AuthorizationServerConfigurerAdapter {

    @Value("${config.oauth2.privateKey}")
    private String privateKey;

    @Value("${config.oauth2.publicKey}")
    private String publicKey;

    @Value("{config.clienturl}")
    private String clientUrl;

    @Autowired
    AuthenticationManager authenticationManager;

    @Bean
    public JwtAccessTokenConverter customTokenEnhancer(){

        JwtAccessTokenConverter customTokenEnhancer = new CustomTokenEnhancer();
        customTokenEnhancer.setSigningKey(privateKey);

        return customTokenEnhancer;
    }

    @Bean
    public JwtTokenStore tokenStore() {
        return new JwtTokenStore(customTokenEnhancer());
    }


    @Override
    public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
        oauthServer
                .tokenKeyAccess("isAnonymous() || hasRole('ROLE_TRUSTED_CLIENT')") // permitAll()
                .checkTokenAccess("hasRole('TRUSTED_CLIENT')"); // isAuthenticated()
    }


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


        .authenticationManager(authenticationManager)
        .tokenStore(tokenStore())
        .accessTokenConverter(customTokenEnhancer())
;
    }

    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {

        String url = clientUrl;

        clients.inMemory()


        .withClient("public") 
        .authorizedGrantTypes("client_credentials", "implicit")
        .scopes("read")
        .redirectUris(url)

        .and()


        .withClient("eagree_web").secret("eagree_web_dev")
        //eagree_web should come from properties file?
        .authorities("ROLE_TRUSTED_CLIENT") 
        .authorizedGrantTypes("client_credentials", "password", "authorization_code", "refresh_token")
        .scopes("read", "write", "trust") 
        .redirectUris(url).resourceIds("dummy");
    }
}

И моя конфигурация сервера ресурсов выглядит следующим образом:

@Configuration
@EnableResourceServer
public class ResourceServerConfiguration  extends ResourceServerConfigurerAdapter {



    @Value("{config.oauth2.publicKey}")
    private String publicKey;

    @Autowired
    CustomTokenEnhancer tokenConverter;

    @Autowired
    JwtTokenStore jwtTokenStore;

    @Bean
    public JwtTokenStore jwtTokenStore() {
        tokenConverter.setVerifierKey(publicKey);
        jwtTokenStore.setTokenEnhancer(tokenConverter);
        return jwtTokenStore;
    }

    @Bean
    public ResourceServerTokenServices defaultTokenServices() {
        final DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenEnhancer(tokenConverter);
        defaultTokenServices.setTokenStore(jwtTokenStore());
        return defaultTokenServices;
    }


    @Override
    public void configure(HttpSecurity http) throws Exception {
        super.configure(http);
        // @formatter:off
        http
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER)
                .and()
                .requestMatchers()
                .antMatchers("/**")
                .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.OPTIONS, "/api/**").permitAll()
                .antMatchers(HttpMethod.GET, "/api/**").access("#oauth2.hasScope('read')")
                .antMatchers(HttpMethod.PATCH, "/api/**").access("#oauth2.hasScope('write')")
                .antMatchers(HttpMethod.POST, "/api/**").access("#oauth2.hasScope('write')")
                .antMatchers(HttpMethod.PUT, "/api/**").access("#oauth2.hasScope('write')")
                .antMatchers(HttpMethod.DELETE, "/api/**").access("#oauth2.hasScope('write')")
                .antMatchers("/admin/**").access("hasRole('ROLE_USER')");

        // @formatter:on
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        System.out.println("Configuring ResourceServerSecurityConfigurer ");
        resources.resourceId("dummy").tokenServices(defaultTokenServices());
    }

}

Мой тестовый пример терпит неудачу, говоря:

{"error": "invalid_token", "error_description": "Невозможно преобразовать токен доступа в JSON"}

Как получить объект аутентификации из JWT? Как проверить подлинность клиента с учетными данными клиента? Как использовать @Secured аннотацию на моих контроллерах ресурсов?

Какой код используется на стороне сервера ресурсов для декодирования токена, чтобы извлекать учетные данные клиента и какой код проверяется на роль пользователя?

Пожалуйста, помогите, поскольку я уже провел 2 дня, ударяя головой по этой, казалось бы, легкой задаче.

Примечание: я получаю маркер с сервера Auth как: {access_token = b5d89a13-3c8b-4bda-b0f2-a6e9d7b7a285, token_type = bearer, refresh_token = 43777224-b6f2-44d7-bf36-4e1934d32cbb, expires_in = 43199, scope = read write trust, authority = [{authority = ROLE_USER}, {authority = ROLE_ADMIN}]}

Пожалуйста, объясните понятия и отметьте, если что-то отсутствует в моей конфигурации. Мне нужно знать лучшие методы настройки моего ресурса и сервера auth, пожалуйста.

Ответ 1

В следующем я имею в виду этот учебник Baeldung, который я уже успешно реализовал: http://www.baeldung.com/spring-security-oauth-jwt

Во-первых: CustomTokenEnhancer используется на стороне AuthorizationServer для улучшения созданного токена с дополнительной пользовательской информацией. Вы должны использовать так называемый DefaultAccessTokenConverter на стороне ResourceServer, чтобы извлечь эти дополнительные претензии.

Вы можете @Autowire CustomAccessTokenConverter в свой класс ResourceServerConfiguration и затем установить его в свою конфигурацию JwtTokenStore().

ResourceServerConfiguration:

@Autowired
private CustomAccessTokenConverter yourCustomAccessTokenConverter;

@Bean
public TokenStore tokenStore() {
    return new JwtTokenStore(accessTokenConverter());
}

@Bean
public JwtAccessTokenConverter accessTokenConverter() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setAccessTokenConverter(yourCustomAccessTokenConverter);
    converter.setSigningKey(yourSigningKey);
    return converter;
}

CustomAccessTokenConverter может быть сконфигурирован, так что пользовательские требования будут извлечены здесь.

CustomAccessTokenConverter:

@Component
public class CustomAccessTokenConverter extends DefaultAccessTokenConverter {

    @Override
    public OAuth2Authentication extractAuthentication(Map<String, ?> claims) {
        OAuth2Authentication authentication = super.extractAuthentication(claims);
        authentication.setDetails(claims);
        return authentication;
    }

}

(см. https://github.com/Baeldung/spring-security-oauth/blob/master/oauth-resource-server-1/src/main/java/org/baeldung/config/CustomAccessTokenConverter.java)