默认情况下OAuth2.0 客户端模式(client_credentials)不支持refresh code。现在由于业务的关系,需要支持refresh code。
在Spring OAuth2.0中 client_credentials模式对应的类是ClientCredentialsTokenGranter
在此类中有个变量可以控制是否返回refreshcode,此成员变量是allowRefresh,默认值为false。在此类的在grant()方法中,如果allowRefresh=false,则会将OAuth2AccessToken实例中的refreshCode值设置为null。所以如果要client_credentials模式返回refreshcode,则只需要调用setAllowRefresh()设置allowRefresh为true即可。
ClientCredentialsTokenGranter.java源码如下:
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 getDefaultTokenGranters() {
ClientDetailsService clientDetails = clientDetailsService();
AuthorizationServerTokenServices tokenServices = tokenServices();
AuthorizationCodeServices authorizationCodeServices = authorizationCodeServices();
OAuth2RequestFactory requestFactory = requestFactory();
List tokenGranters = new ArrayList();
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已经有值,则不会进行初始化
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 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 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();
}
}