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!