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值成功执行刷新:
在这里插入图片描述
相关文章
相关标签/搜索