2017-09-25 135 views
1

我能夠將附加信息包含到實現我自己的令牌增強器的訪問令牌中,但這些信息包含兩次。一個在編碼的access_token中,另一個在auth服務器響應中。Spring OAuth 2 + JWT包含訪問令牌中的附加信息

長話短說!我請求與正確的憑據的訪問令牌,我得到這樣的響應:

{ 
    "access_token" : "eyJhbGciOiJSUzI1NiJ9.eyJjbGllbnRJZCI6Ik1ZX0NVU1RPTV9JTkZPX0NMSUVOVCIsInVzZXJfbmFtZSI6IlVTRVIiLCJzY29wZSI6WyJGT08iXSwiZXhwIjoxNTA2MzkwOTM5LCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiZjJkYWFkM2ItYzkzOC00ZjExLWI3ODctMzExZDdlNjYzYzhhIiwiY2xpZW50X2lkIjoid2ViX2FwcCJ9.IdgYRxwZGRPR97nxHpAcJXNWDTShQE1tsg9NsBwlOk8eDWE1B-mjfGTaKiyTO1-m9GBpXnxt2PaOV7AbdLsCZ5xLPUR0_5ehuNB6WCXLSkdac5xbw-rmNdJHTe9gLJizOZAKF6J-_Xo9OOQISKBqliY5vo5y0btqIw4CX6-ukYoWZmwHThwnAsEA_PqGuEXsbXMGz-vqJaSVpvJeEOBNL0KOh-cNxc0ft-rJ3snjPerN_efAiZdFkzxdCeuoGmZvSyHRjYR8kQ3ZqZ5MOunw9YuTvidL1IK5TODHQ2BjiCTpbgDlYx-Oh5UxcYNrPOhD-tBjRuuqDSz8K6ddpke4RQ", 
    "token_type" : "bearer", 
    "refresh_token" : "eyJhbGciOiJSUzI1NiJ9.eyJjbGllbnRJZCI6Ik1ZX0NVU1RPTV9JTkZPX0NMSUVOVCIsInVzZXJfbmFtZSI6IlVTRVIiLCJzY29wZSI6WyJGT08iXSwiYXRpIjoiZjJkYWFkM2ItYzkzOC00ZjExLWI3ODctMzExZDdlNjYzYzhhIiwiZXhwIjoxNTA4OTM5NzM5LCJhdXRob3JpdGllcyI6WyJST0xFX1VTRVIiXSwianRpIjoiOGU2Zjc0OTEtMmQ3MC00NTUwLThhMDgtZjk0YjkzYTVkYWZmIiwiY2xpZW50X2lkIjoid2ViX2FwcCJ9.MqwMrYrofu7pUQu2mF33__h6M4OWSRrQ-lc8JzTn0DkpJ6a3-yjnjjppZ9fs3KBz_lpRIO8jo--eId449rEjP4M3_9lDRSW9_HyBAvd57OtyUHa5SPM9prD6ReXGCyiIw2gO07euIf-Vp4UHsjoKK0MdtfMmFIWms1JMGFBmzBha8kqKaMxKzppGy-jVdP7384K9oovD20H-NubjScfoO2Crp1cTM-SXc-0v6kwB1qV-cI6HKXmbkoFhbH2bL_nRvXTkLYI-UvRNTNLHzqhcqztLTrszcWa2BjNU2IofsNByFS8BHTDV1vu0BqZA4kfNCJcFJ89tBDt2L8vfFkYezQ", 
    "expires_in" : 43199, 
    "scope" : "FOO", 
    "clientId" : "MY_CUSTOM_INFO_CLIENT", 
    "jti" : "f2daad3b-c938-4f11-b787-311d7e663c8a" 
} 

所以我能看到的clientId包括在響應......現在,我複製我和的access_token我解碼:https://jwt.io/

而且在有效載荷也包括clientId ...

我的問題是:如何從服務器響應中刪除附加信息,並將它留在令牌(access_token和refresh_token)中。

請參閱下面的代碼:

import java.util.Arrays; 

import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.beans.factory.annotation.Qualifier; 
import org.springframework.context.annotation.Bean; 
import org.springframework.context.annotation.Configuration; 
import org.springframework.context.annotation.Primary; 
import org.springframework.core.io.ClassPathResource; 
import org.springframework.security.authentication.AuthenticationManager; 
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter; 
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer; 
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer; 
import org.springframework.security.oauth2.provider.token.DefaultTokenServices; 
import org.springframework.security.oauth2.provider.token.TokenEnhancer; 
import org.springframework.security.oauth2.provider.token.TokenEnhancerChain; 
import org.springframework.security.oauth2.provider.token.TokenStore; 
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter; 
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; 
import org.springframework.security.oauth2.provider.token.store.KeyStoreKeyFactory; 

@Configuration 
@EnableAuthorizationServer 
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { 

    @Autowired 
    @Qualifier("authenticationManagerBean") 
    private AuthenticationManager authenticationManager; 

    @Override 
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { 
     TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain(); 
     tokenEnhancerChain.setTokenEnhancers(
        Arrays.asList(tokenEnhancer(), accessTokenConverter())); 
     endpoints 
       .tokenStore(tokenStore()) 
       .authenticationManager(authenticationManager) 
       .tokenEnhancer(tokenEnhancerChain); 
    } 
    @Override 
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception { 

     clients.inMemory() 
      .withClient("web_app") 
      .secret("web_app123") 
      .scopes("FOO") 
      .autoApprove(true) 
      .authorities("FOO_READ", "FOO_WRITE") 
      .authorizedGrantTypes("refresh_token", "password"); 
} 
    @Bean 
    public TokenStore tokenStore() { 
     return new JwtTokenStore(accessTokenConverter()); 
    } 

    @Bean 
    public JwtAccessTokenConverter accessTokenConverter() { 
     JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 
     KeyStoreKeyFactory keyStoreKeyFactory = 
      new KeyStoreKeyFactory(new ClassPathResource("mykey.jks"), "mykey123".toCharArray()); 
     converter.setKeyPair(keyStoreKeyFactory.getKeyPair("mykey")); 
     return converter; 
    } 

    @Bean 
    @Primary 
    public DefaultTokenServices tokenServices() { 
     DefaultTokenServices defaultTokenServices = new DefaultTokenServices(); 
     defaultTokenServices.setTokenStore(tokenStore()); 
     defaultTokenServices.setSupportRefreshToken(true); 
     return defaultTokenServices; 
    } 

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

而且我CustomTokenEnhancer:

import java.util.HashMap; 
import java.util.Map; 

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 com.mapflow.ms.security.service.UserDetailInfo; 

public class CustomTokenEnhancer implements TokenEnhancer { 

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

     additionalInfo.put("clientId", user.getClientId()); 

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

     return accessToken; 
    } 
} 

回答

1

一段時間,我想通了之後。 JwtAccessTokenConverter也實現了TokenEnhaner。首先調用CustomTokenEnhaner.enhance,包括附加信息。然後JwtAccessTokenConverter.enhance,通過CustomTokenEnhaner.enhance對AccessToken進行編碼,幷包括響應的附加信息。該想法初始化爲DefaultOAuth2AccessToken.additionalInformation,一次編碼在access_token中。解決辦法是:

首先讓CustomTokenEnhancer延伸JwtAccessTokenConverter,覆蓋enhance,附加額外的信息,請從父enhance並初始化DefaultOAuth2AccessToken.additionalInformation

public class CustomTokenConverter extends JwtAccessTokenConverter { 

    @Override 
    public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, 
      OAuth2Authentication authentication) { 
     if(authentication.getOAuth2Request().getGrantType().equalsIgnoreCase("password")) { 
      UserDetailInfo user = (UserDetailInfo) authentication.getPrincipal(); 
      final Map<String, Object> additionalInfo = new HashMap<String, Object>(); 

      additionalInfo.put("clientId", user.getClientId()); 

      ((DefaultOAuth2AccessToken) accessToken) 
        .setAdditionalInformation(additionalInfo);  
     } 
     accessToken = super.enhance(accessToken, authentication); 
     ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(new HashMap<>()); 
     return accessToken; 
    } 
} 

而最後一步,將刪除豆

@Bean 
    public JwtAccessTokenConverter accessTokenConverter() { 
     JwtAccessTokenConverter converter = new JwtAccessTokenConverter(); 
     KeyStoreKeyFactory keyStoreKeyFactory = 
      new KeyStoreKeyFactory(new ClassPathResource("mykey.jks"), "mykey123".toCharArray()); 
     converter.setKeyPair(keyStoreKeyFactory.getKeyPair("mykey")); 
     return converter; 
    } 

並將該密鑰添加到CustomTokenEnhancer

@Bean 
public JwtAccessTokenConverter accessTokenConverter() { 
    CustomTokenConverter tokenConverter = new CustomTokenConverter(); 
    tokenConverter.setSigningKey("PswMapview2017"); 
    return tokenConverter; 
} 

就是這樣。