Spring cloud系列20 OAuth2.0的实现客户端模式(client_credentials)支持refesh code 桃扇骨 2021-12-04 05:29 1266阅读 0赞 默认情况下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<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已经有值,则不会进行初始化 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(); } } 改造完成进行测试代码: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hyeTIwMTU_size_16_color_FFFFFF_t_70] 测试结果,使用获取refresh\_token值成功执行刷新: ![在这里插入图片描述][watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hyeTIwMTU_size_16_color_FFFFFF_t_70 1] [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hyeTIwMTU_size_16_color_FFFFFF_t_70]: /images/20211204/0d6cb3a942764124b095f2ae4ce1d1be.png [watermark_type_ZmFuZ3poZW5naGVpdGk_shadow_10_text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2hyeTIwMTU_size_16_color_FFFFFF_t_70 1]: /images/20211204/af6bcc3885784b5c92eb7ec93cea4a4e.png
还没有评论,来说两句吧...