Source Code Implementation Resolution of Token Transfer in Spring Cloud OAuth Micro-Service

Keywords: Web Server Spring

Background analysis

  • 1. The client carries the token issued by the authentication center and requests the resource server A.( Spring Security OAuth Issues Token Source Parsing)
  • 2. Clients carry tokens to access the resource server directly, and the resource server checks token ([Spring Cloud OAuth2 Resource Server CheckToken source code parsing)
    ](https://my.oschina.net/giegie/blog/3005999) ) Judge user legitimacy and save it in context
  • 3.A service interface receives requests and needs to assemble the returned data by invoking B services through Feign or other RPC frameworks

This paper mainly discusses the source code implementation of the third A - > B, token self-maintenance.

How to Implement token Transfer

Configure OAuth 2 FeignRequest Interceptor

  • This is Feign's interceptor implementation

@Bean
@ConditionalOnProperty("security.oauth2.client.client-id")
public RequestInterceptor oauth2FeignRequestInterceptor(OAuth2ClientContext oAuth2ClientContext,
                                                        OAuth2ProtectedResourceDetails resource,) {
    return new OAuth2FeignRequestInterceptor(oAuth2ClientContext, resource);
}

Source code analysis

  • Get the token in the context and assemble it into the request header
public class OAuth2FeignRequestInterceptor implements RequestInterceptor {
    // Add token to the request
    @Override
    public void apply(RequestTemplate template) {
        template.header(header, extract(tokenType));
    }
    
    protected String extract(String tokenType) {
        OAuth2AccessToken accessToken = getToken();
        return String.format("%s %s", tokenType, accessToken.getValue());
    }

    // Getting token from spring security context
    public OAuth2AccessToken getToken() {

        OAuth2AccessToken accessToken = oAuth2ClientContext.getAccessToken();
        if (accessToken == null || accessToken.isExpired()) {
            try {
                accessToken = acquireAccessToken();
            }
        }
        return accessToken;
    }

}
  • Let's look at AccessTokenContextRelay, context token transponder. It's very simple to get authentication information from context and put token into context.
public class AccessTokenContextRelay {

    private OAuth2ClientContext context;

    public AccessTokenContextRelay(OAuth2ClientContext context) {
        this.context = context;
    }
    
    public boolean copyToken() {
        if (context.getAccessToken() == null) {
            Authentication authentication = SecurityContextHolder.getContext()
                    .getAuthentication();
            if (authentication != null) {
                Object details = authentication.getDetails();
                if (details instanceof OAuth2AuthenticationDetails) {
                    OAuth2AuthenticationDetails holder = (OAuth2AuthenticationDetails) details;
                    String token = holder.getTokenValue();
                    DefaultOAuth2AccessToken accessToken = new DefaultOAuth2AccessToken(
                            token);
                    String tokenType = holder.getTokenType();
                    if (tokenType != null) {
                        accessToken.setTokenType(tokenType);
                    }
                    context.setAccessToken(accessToken);
                    return true;
                }
            }
        }
        return false;
    }

}
  • When to perform the transit, the oauth2 resource server is very simple and violent, adding an interceptor to forward.

The source code is very simple

On the implementation of spring security oauth

  1. When the request is online without Token, if feign is called directly, the OAuth2FeignRequest Interceptor will surely report an error because the context copy fails.
  2. If thread isolation is set, there will also be an error. Causes security issues up and down to be passed out of the sub-threads.
  3. Mandatory use of interceptors to process token forwarding to this context, where only business scenarios are used, with high performance impact

These three problems will certainly be encountered in the process of using them.

Customize OAuth2FeignRequest Interceptor

  • Whether token transit is performed through external conditions
public void apply(RequestTemplate template) {
    Collection<String> fromHeader = template.headers().get(SecurityConstants.FROM);
    if (CollUtil.isNotEmpty(fromHeader) && fromHeader.contains(SecurityConstants.FROM_IN)) {
        return;
    }

    accessTokenContextRelay.copyToken();
    if (oAuth2ClientContext != null
        && oAuth2ClientContext.getAccessToken() != null) {
        super.apply(template);
    }
}
  • Manually calling copy of accessTokenContextRelay, of course, requires overwriting the configuration of the native oauth client

Posted by daok on Sat, 11 May 2019 06:56:23 -0700