默认状况下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