Spring cloud系列20 OAuth2.0的實現客戶端模式(client_credentials)支持refesh code

默認狀況下OAuth2.0 客戶端模式(client_credentials)不支持refresh code。如今因爲業務的關係,須要支持refresh code。java

在Spring OAuth2.0中 client_credentials模式對應的類是ClientCredentialsTokenGranter 在此類中有個變量能夠控制是否返回refreshcode,此成員變量是allowRefresh,默認值爲false。在此類的在grant()方法中,若是allowRefresh=false,則會將OAuth2AccessToken實例中的refreshCode值設置爲null。因此若是要client_credentials模式返回refreshcode,則只須要調用setAllowRefresh()設置allowRefresh爲true便可。redis

ClientCredentialsTokenGranter.java源碼以下:bash

public class ClientCredentialsTokenGranter extends AbstractTokenGranter {

        private static final String GRANT_TYPE = "client_credentials";
        private boolean allowRefresh = false;

        // 能夠設置
        public void setAllowRefresh(boolean allowRefresh) {
                this.allowRefresh = allowRefresh;
        }

        @Override
        public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
                OAuth2AccessToken token = super.grant(grantType, tokenRequest);
                if (token != null) {
                        DefaultOAuth2AccessToken norefresh = new DefaultOAuth2AccessToken(token);
                        // The spec says that client credentials should not be allowed to get a refresh token
                        if (!allowRefresh) {
                                // 刪除refresh code的值
                                norefresh.setRefreshToken(null);
                        }
                        token = norefresh;
                }
                return token;
        }

}
複製代碼

那麼系統在哪裏初始化ClientCredentialsTokenGranter 值呢?通過debug後,發如今AuthorizationServerEndpointsConfigurer的私有方法tokenGranter中。此方法在調用時,若是發現tokenGranter 爲空,則進行初始化。服務器

private TokenGranter tokenGranter() {
     if (tokenGranter == null) {
             tokenGranter = new TokenGranter() {
                     private CompositeTokenGranter delegate;

     @Override
     public OAuth2AccessToken grant(String grantType, TokenRequest tokenRequest) {
             if (delegate == null) {
                      // 默認請求下,會調用此方法初始化Granter,重點是getDefaultTokenGranters()方法
                     delegate = new CompositeTokenGranter(getDefaultTokenGranters());
             }
             return delegate.grant(grantType, tokenRequest);
     }
     };
     }
     return tokenGranter;
}
//  在這個方法中初始化ClientCredentialsTokenGranter等Granter
private List<TokenGranter> getDefaultTokenGranters() {
     ClientDetailsService clientDetails = clientDetailsService();
     AuthorizationServerTokenServices tokenServices = tokenServices();
     AuthorizationCodeServices authorizationCodeServices = authorizationCodeServices();
     OAuth2RequestFactory requestFactory = requestFactory();

     List<TokenGranter> tokenGranters = new ArrayList<TokenGranter>();
     tokenGranters.add(new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices, clientDetails,
             requestFactory));
     tokenGranters.add(new RefreshTokenGranter(tokenServices, clientDetails, requestFactory));
     ImplicitTokenGranter implicit = new ImplicitTokenGranter(tokenServices, clientDetails, requestFactory);
     tokenGranters.add(implicit);
     // 建立client_credentials模式的處理類
     tokenGranters.add(new ClientCredentialsTokenGranter(tokenServices, clientDetails, requestFactory));
     if (authenticationManager != null) {
             tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices,
                     clientDetails, requestFactory));
     }
     return tokenGranters;
     }
複製代碼

如今咱們要使用本身建立的TokenGranter,而不是默認值,AuthorizationServerEndpointsConfigurer有個 tokenGranter(TokenGranter)能夠用來設置自定義的TokenGranter。經過這個方法設置TokenGranter後,調用tokenGranter()時發現tokenGranter已經有值,則不會進行初始化ide

public AuthorizationServerEndpointsConfigurer tokenGranter(TokenGranter tokenGranter) {
        this.tokenGranter = tokenGranter;
        return this;
}
複製代碼

最後,在OAuth2AuthorizationServer的configure(AuthorizationServerEndpointsConfigurer)方法中使用endpoints.tokenGranter()配置自定義granter。@Bean方法getCustomizedTokenGranters()方法返回自定義的TokenGranter的列表。 此類中其餘實例都是自定義的組件替換系統默認的組件,這裏略。測試

// 受權服務器配置
@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServer extends AuthorizationServerConfigurerAdapter {

    @Autowired
    private MyClientDetailsService myClientDetailsService;

    @Autowired
    private RedisTokenStore redisTokenStore;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private MyUserDetailsService myUserDetailsService;
    @Autowired
    private AuthorizationServerTokenServices authorizationServerTokenServices;

    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        // 自定義granters
        endpoints.tokenGranter(new CompositeTokenGranter(getCustomizedTokenGranters()));
    }

    @Bean
    @Primary
    public AuthorizationServerTokenServices tokenServices() {
        DefaultTokenServices tokenServices = new DefaultTokenServices();
        tokenServices.setSupportRefreshToken(true);
        tokenServices.setTokenStore(redisTokenStore);
        tokenServices.setClientDetailsService(myClientDetailsService);
        return tokenServices;
    }

    private List<TokenGranter> getCustomizedTokenGranters() {
        AuthorizationServerTokenServices tokenServices = tokenServices();
        ClientDetailsService clientDetails = myClientDetailsService;
        AuthorizationCodeServices authorizationCodeServices = authorizationCodeServices();
        OAuth2RequestFactory requestFactory = new DefaultOAuth2RequestFactory(clientDetails);

        AuthorizationCodeTokenGranter authorizationCodeTokenGranter = new AuthorizationCodeTokenGranter(tokenServices, authorizationCodeServices, clientDetails, requestFactory);
        RefreshTokenGranter refreshTokenGranter = new RefreshTokenGranter(tokenServices, clientDetails, requestFactory);
        ImplicitTokenGranter implicit = new ImplicitTokenGranter(tokenServices, clientDetails, requestFactory);
        ClientCredentialsTokenGranter clientCredentialsTokenGranter = new ClientCredentialsTokenGranter(tokenServices, clientDetails, requestFactory);
        // 設置返回refresh code
        clientCredentialsTokenGranter.setAllowRefresh(true); AuthorizationServerEndpointsConfigurer.getDefaultTokenGranters

        List<TokenGranter> tokenGranters = new ArrayList<>();
        tokenGranters.add(authorizationCodeTokenGranter);
        tokenGranters.add(refreshTokenGranter);
        tokenGranters.add(implicit);
        tokenGranters.add(clientCredentialsTokenGranter);
        if (authenticationManager != null) {
            tokenGranters.add(new ResourceOwnerPasswordTokenGranter(authenticationManager, tokenServices, clientDetails, requestFactory));
        }

        return tokenGranters;
    }

    @Bean
    public AuthorizationCodeServices authorizationCodeServices() {
        // TODO 若是要使用這個值,則須要存儲到redis中,https://blog.csdn.net/dong_19890208/article/details/74914852
        return new InMemoryAuthorizationCodeServices();
    }

}
複製代碼

改造完成進行測試代碼: ui

在這裏插入圖片描述
測試結果,使用獲取refresh_token值成功執行刷新:
在這裏插入圖片描述
相關文章
相關標籤/搜索