J'ai vu dans certaines implémentations de oauth2 des informations supplémentaires sur la réponse renvoyée par le serveur d'autorisations lorsqu'il émet des jetons d'accès. Je me demande s'il existe un moyen d'y parvenir en utilisant spring-security-oauth2. J'aimerais pouvoir inclure des autorités d'utilisateur dans la réponse au jeton d'accès afin que mes applications consommatrices n'aient pas besoin de gérer les autorisations d'utilisateur mais puissent toujours définir l'utilisateur dans leurs propres contextes de sécurité et appliquer l'une de leurs propres sources. chèques.
Je suppose qu'une autre option consisterait à utiliser des jetons JWT et à partager les informations appropriées avec les applications clientes afin qu'elles puissent analyser l'utilisateur/les autorités du jeton et le définir en fonction du contexte. Cela me rend encore plus mal à l'aise, car je préférerais savoir quelles applications clientes pourraient avoir accès à ces informations (applications de confiance uniquement) et, autant que je sache, le serveur d'autorisation et le serveur de ressources devraient savoir comment analyser les jetons JWT.
Vous devrez implémenter un TokenEnhancer personnalisé comme ceci:
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;
}
}
et l'ajouter à votre AuthorizationServerConfigurerAdapter en tant que bean avec les paramètres correspondants
@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();
}
}
puis dans un contrôleur (par exemple)
@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;
}
}
J'utilise personnellement un TokenStore JDBC, donc mes "éléments auto-câblés ici" correspondent à des sources de données @Autowired, PasswordEncoder et autres.
J'espère que cela a aidé!
Si vous utilisez les variables JwtAccessTokenConverter
ou DefaultAccessTokenConverter
de Spring, vous pouvez ajouter votre CustomTokenEnhancer personnalisé (voir la première réponse) et l'appliquer à l'aide de TokenEnhancerChain comme ceci:
@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();
}
Une autre solution consiste à créer un TokenConverter personnalisé qui étend la variable JwtAccessTokenConverter
de Spring et à remplacer la méthode enhan () par vos revendications personnalisées.
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);
}
}
Et alors:
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.tokenStore(tokenStore())
.tokenEnhancer(customTokenEnhancer())
.authenticationManager(authenticationManager);
}
@Bean public CustomTokenConverter customTokenEnhancer() {
return new CustomTokenConverter();
}
Ensemble avec:
@Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
Vous devez inclure
@Bean
public DefaultAccessTokenConverter accessTokenConverter() {
return new DefaultAccessTokenConverter();
}
et ajoutez tout à la configuration des noeuds finaux:
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore)
.tokenEnhancer(tokenEnhancer())
.accessTokenConverter(accessTokenConverter())
.authorizationCodeServices(codeServices)
.authenticationManager(authenticationManager)
;
}
Sans cela, votre CustomTokenEnhancer ne fonctionnera pas.
package com.security;
import Java.util.HashMap;
import Java.util.Map;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.oauth2.common.DefaultOAuth2AccessToken;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.token.TokenEnhancer;
import org.springframework.stereotype.Component;
@Component
public class CustomTokenEnhancer implements TokenEnhancer {
@Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken,
OAuth2Authentication authentication) {
// TODO Auto-generated method stub
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;
}
}
Voici la configuration XML:
<bean id="tokenEnhancer" class="com.security.CustomTokenEnhancer" />
<!-- Used to create token and and every thing about them except for their persistence that is reposibility of TokenStore (Given here is a default implementation) -->
<bean id="tokenServices" class="org.springframework.security.oauth2.provider.token.DefaultTokenServices">
<property name="tokenStore" ref="tokenStore" />
<property name="accessTokenValiditySeconds" value="30000000"></property>
<property name="refreshTokenValiditySeconds" value="300000000"></property>
<property name="supportRefreshToken" value="true"></property>
<property name="clientDetailsService" ref="clientDetails"></property>
<property name="tokenEnhancer" ref="tokenEnhancer" />
</bean>
C'est ainsi que j'ai pu ajouter des informations supplémentaires au jeton.
créer un fichier de classe CustomTokenEnhancer
@Component
public class CustomTokenConverter étend JwtAccessTokenConverter {
@Override Public OAuth2AccessToken améliorer (OAuth2AccessToken accessToken, authentification OAuth2Authentication) {
final Map<String, Object> additionalInfo = new HashMap<>(); additionalInfo.put("customized", "true"); User user = (User) authentication.getPrincipal(); additionalInfo.put("role", user.getAuthorities().stream().map(GrantedAuthority::getAuthority).collect(Collectors.toList())); ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo); return super.enhance(accessToken, authentication); }
} </ pre> 2. coller le code écrit ci-dessous dans AuthorizationServerConfig
@Passer outre public void configure (noeuds finaux AuthorizationServerEndpointsConfigurer) lève une exception { TokenEnhancerChain enhancerChain = new TokenEnhancerChain (); enhancerChain.setTokenEnhancers (Arrays.asList (customTokenEnhancer (), accessTokenConverter ()));endpoints .tokenStore(tokenStore()) .tokenEnhancer(customTokenEnhancer()) .authenticationManager(authenticationManager); } @Bean protected JwtAccessTokenConverter jwtTokenEnhancer() { JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); converter.setSigningKey("my_signing_key"); return converter; } @Bean public CustomTokenConverter customTokenEnhancer() { return new CustomTokenConverter(); } @Bean public TokenStore tokenStore() { return new JdbcTokenStore(dataSource); }
</ pre>
- importer les bibliothèques appropriées après avoir collé les codes ci-dessus