Как настроить Resource Server в Spring Security, чтобы он использовал дополнительную информацию в токене JWT
У меня есть сервер токенов oauth2 jwt, настроенный для установки дополнительной информации о полномочиях пользователей.
@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.
Моя конфигурация сервера аутентификации выглядит так:
@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 дня, стуча головой по этой, казалось бы, легкой задаче.
Примечание. Я получаю токен с сервера аутентификации как: полномочия = [{орган = ROLE_USER}, {орган = ROLE_ADMIN}]}
Пожалуйста, объясните концепции и укажите, если что-то отсутствует в моей конфигурации. Мне нужно знать лучшие практики по настройке моего ресурса и сервера авторизации, пожалуйста.