SoFunction
Updated on 2025-03-08

SpringCloud solves the problem of missing feign call token

Background discussion

feign request

In a microservice environment, completing an http request often requires calling several other services to complete its functions. This situation is very common and cannot be avoided. Then, the service needs to initiate a request through feignClient to obtain the required ones.resource

Authentication and authentication

Generally speaking, in the microservice project deployment environment, each microservice is run in the intranet environment, and the gateway service is responsible for requesting it.routing, expose it to the requester through nginx.

In this case, it seems that the gateway does one hereCertification, it can ensure that the requester is legal. As for microservices calling microservices, they are all their own people anyway, and they are intranets, so it doesn’t matter whether they have verified their identity.

I have a friend, their company's projects are indeed doing this, serious business projects.

To be honest, as long as the framework provides such a function, it has meaning. However, if permission verification is involved, the feign call between microservices needs to be known.identityIt needs to be doneAuthentication

token

Whether it is JWT, OAUTH2, or shiro, the more recognized authentication and authentication solution is to put a bunch of things in the request header, and then the service provider completes authentication and authentication by parsing these things. These things are commonly known astoken

What needs to be solved in feign call is the problem of token delivery. Only when the request initiator passes the correct token to the service provider can the service provider complete authentication and authentication, and then return the required oneresource

Problem description

You may encounter the following problems in feign calls:

  • In synchronous calls, the token is lost. This can be solved by creating an interceptor and passing the token through.
  • In asynchronous calls, the token is lost, so it cannot be directly transmitted because the child thread does not have it.token, this requires first passing the token from the parent thread to the child thread, and then passing it through

Solution

token transmission

Write an interceptor that passes the token carried by the http request to restTemplate before the feign request.

The specific implementation method is:

  • Create a RequestInterceptor interface in Component implementation

  • Rewrite the apply method

  • Get RequestAttributes through RequestContextHolder object

  • Get HttpServletRequest through RequestAttributes object

  • Get the request header through the HttpServletRequest object

  • Take out the token in the request header

  • Stuff the token into the http request header created by restTemplate

Sample code:

BizFeignRequestInterceptor

import ;
import ;
import ;
import ;
import ;
import ;
import ;
import .slf4j.Slf4j;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
@Slf4j
@Order(1)
@Component
public class BizFeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        RequestAttributes attributes = ();
        if (null! = attributes) {
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) attributes;
            String token = ().getHeader("token");
            ("token",token);
        }
    }
}

token asynchronous thread delivery

The above-mentioned addition of BizFeignRequestInterceptor can only solve the problem of token delivery in a synchronous call environment, and it will be GG in an asynchronous thread environment.

By actively passing the RequestAttribute to the child thread in the main thread, the problem of token passing in some asynchronous threads can be solved. The example code is as follows:

((), true);

However, this method has disadvantages. When the main thread ends before the child thread, the child thread will not get the RequestAttribute, because Tomcat will clear the data when the http request ends.

We can create an InheritableThreadLocal to save the RequestAttribute, which will solve the problem perfectly.

The implementation idea is:

  • Create a RequestAttributeContext, which maintains an InheritableThreadLocal object to store RequestAttributes

  • Create a RequestAttributeInterceptor, implement HandlerInterceptor, WebMvcConfigurer interface, which is used to set the request before the start of the request.RequestAttributesStored in RequestAttributeContext

  • Modify BizFeignRequestInterceptor and when RequestAttributes cannot be obtained, get it from RequestAttributeContext

  • Transmission logic remains unchanged

The relevant example code is as follows:

RequestAttributeContext

import ;
import .slf4j.Slf4j;
import ;
@Slf4j
public class RequestAttributeContext {
    private static final ThreadLocal<RequestAttributes> context = new InheritableThreadLocal<>();
    public static void setAttribute(RequestAttributes attributes) {
        if (null == attributes) {
            ("RequestAttributes is null");
        }
        (attributes);
    }
    public static RequestAttributes getAttribute() {
        return ();
    }
    public static void removeAttribute() {
        ();
    }
}

RequestAttributeInterceptor

import ;
import ;
import .slf4j.Slf4j;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
@Slf4j
@Configuration
public class RequestAttributeInterceptor implements HandlerInterceptor, WebMvcConfigurer {
    /**
      * Rewrite the addInterceptors of WebMvcConfigurer and add RequestAttributeInterceptor to the interceptor list
      *
      * @param registry
      */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        (this).addPathPatterns("/**").excludePathPatterns("/swagger-resources/**", "/v2/api-docs/**");
     }
     /**
      * Rewrite the preHandle of HandlerInterceptor, and save the RequestAttribute into the RequestAttributeContext before the request starts processing.
      *
      * @param request current HTTP request
      * @param response current HTTP response
      * @param handler chosen handler to execute, for type and/or instance evaluation
      * @return
      * @throws Exception
      */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        RequestAttributes requestAttributes = ();
        (requestAttributes);
        return true;
    }
}

BizFeignRequestInterceptor

import ;
import ;
import ;
import ;
import ;
import ;
import ;
import .slf4j.Slf4j;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
@Slf4j
@Order(1)
@Component
public class BizFeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        RequestAttributes attributes = ();
        if (null! = attributes) {
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) attributes;
            String token = ().getHeader("token");
            ("token",token);
        }else {
            RequestAttributes requestAttributes = ();
            if (null != requestAttributes) {
                (requestAttributes);
            } else {
                ("requestAttributes is null");
            }
            ServletRequestAttributes servletRequestAttributes = (ServletRequestAttributes) requestAttributes;
            String token = ().getHeader("token");
            ("token",token);
        }
    }
}

This is the end of this article about SpringCloud's solution to the problem of missing feign call token in SpringCloud. For more related content lost feign call token in SpringCloud, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!