默認狀況下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值成功執行刷新: