2015-02-13 7 views
15

Ho visto in alcune implementazioni oauth ulteriori informazioni sulla risposta restituita dal server di autorizzazione quando emette i token di accesso. Mi chiedo se c'è un modo per farlo usando spring-security-oauth2. Mi piacerebbe poter includere alcune autorizzazioni utente sulla risposta del token di accesso in modo che le mie applicazioni che consumano non debbano gestire le autorizzazioni degli utenti, ma possono ancora impostare l'utente nei propri contesti di sicurezza e applicare una qualsiasi delle proprie funzionalità di sicurezza primarie controlli.posso includere informazioni utente durante l'emissione di un token di accesso?

  1. Come posso ottenere tali informazioni sulla risposta del token di accesso?
  2. Come posso intercettare le informazioni sul lato client oauth2 e impostarle nel contesto di sicurezza?

Suppongo che un'altra opzione sarebbe utilizzare i token JWT e condividere le informazioni appropriate con le applicazioni client in modo che possano analizzare l'utente/le autorità fuori dal token e impostarlo nel contesto. Ciò mi rende più scomodo poiché preferirei avere il controllo di quali applicazioni client potrebbero avere accesso a queste informazioni (solo app sicure) e AFAIK solo il server delle autorizzazioni e il server delle risorse dovrebbero sapere come analizzare i token JWT.

+0

FWIW le mie preoccupazioni al momento intorno applicazioni JWT e che hanno la capacità di analizzare le informazioni erano mal fondate. In alcuni casi, questo potrebbe essere completamente a posto! Nei casi più restrittivi puoi usare JWE e essere giudizioso su chi condividi la chiave. – RutledgePaulV

risposta

32

Sarà necessario implementare un TokenEnhancer personalizzato in questo modo:

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; 
    } 

} 

e aggiungerlo al AuthorizationServerConfigurerAdapter come un fagiolo con i corrispondenti setter

@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(); 
    } 

} 

poi in un controllore (per esempio)

@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; 
    } 

} 

Personalmente utilizzo un TokenStore JDBC quindi il mio "Alcune cose autowired qui" sono corrispondenti ad alcuni @Autowired Datasource, PasswordEncoder e cosa no.

Spero che questo ha aiutato!

+0

Ho implementato quello che hai suggerito, vedo che il token enhancer viene chiamato quando viene generato il token, ma quando vedo il token nella risposta che ho ricevuto quando chiamo /oauth/token, non vedo le informazioni aggiuntive I aggiunto nel potenziatore. Qualche idea? –

+0

@PedroMadrid non sono sicuro del motivo per cui non viene visualizzato nel risultato ... Hai aggiunto un 'logger.info (" Qui ")' (per esempio) solo per assicurarti che entri nel tuo CustomTokenEnhancer? Chiamando il setAdditionalInformation() sul token e aggiungendo le informazioni, tutto dovrebbe essere buono da lì. – Philippe

+1

grazie per la risposta! Per poeple using JDBC Token il bean 'tokenServices()' deve avere '.setTokenStore (tokenStore)' riga aggiunta sopra enhancer – kiedysktos

2

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 { 
 

 
\t @Override 
 
\t public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, 
 
\t \t \t OAuth2Authentication authentication) { 
 
\t \t // TODO Auto-generated method stub 
 
\t \t 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; 
 
\t } 
 

 
}

Segue la configurazione 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>

È così che sono stato in grado di aggiungere informazioni supplementari al token.

+0

Grazie per aver incluso le importazioni. – kooker

3

Insieme:

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

Bisogna includere

@Bean 
public DefaultAccessTokenConverter accessTokenConverter() { 
    return new DefaultAccessTokenConverter(); 
} 

e aggiungere tutto per endpoint config:

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

     endpoints 
       .tokenStore(tokenStore) 
       .tokenEnhancer(tokenEnhancer()) 
       .accessTokenConverter(accessTokenConverter()) 
       .authorizationCodeServices(codeServices) 
       .authenticationManager(authenticationManager) 
     ; 
    } 

Senza di esso, il tuo CustomTokenEnhancer non funzionerà.

+1

Grazie per la risposta pulita. Infatti accessTokenConverter non è necessario in configurazione se non lo usi. Il set minimo è 'endpoints.tokenStore (tokenStore) .tokenEnhancer (tokenEnhancer()). AuthenticationManager (authenticationManager);'. – kiedysktos

6

Se si utilizza Primavera JwtAccessTokenConverter o DefaultAccessTokenConverter è possibile aggiungere la vostra abitudine CustomTokenEnhancer (vedi prima risposta) ed applicarlo utilizzando una TokenEnhancerChain come questo:

@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(); 
} 

Un'altra soluzione è quella di creare un custom TokenConverter che estende Spring JwtAccessTokenConverter e sovrascrive il metodo con le dichiarazioni personalizzate.

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); 
    } 
} 

E poi:

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

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

@Bean public CustomTokenConverter customTokenEnhancer() { 
    return new CustomTokenConverter(); 
} 
+0

La tua soluzione sta funzionando molto bene per me usando le configurazioni descritte da te! Ora sono in grado di fornire informazioni facendo una richiesta di token! –

Problemi correlati