In the process of Spring Cloud microservice invocation, you need to deal with token relaying, which is the only way to ensure the delivery of user authentication information in the invocation chain. Today we will share how to implement token relay in Feign.
Token Relay
To be clear, this means that the Token token is passed on between services to ensure that the resource server can properly authenticate the caller.
Couldn’t the token be automatically relayed at Feign?
If we carry a Token to access Service A, Service A can definitely authenticate, but Service A calls Service B through Feign, and then A’s token cannot be passed directly to Service B.
Here to briefly explain the reason, the call between services through the Feign interface to carry out. On the caller side, we usually write a Feign interface like the following.
|
|
When we call the Feign interface, a dynamic proxy is used to generate the proxy class for the interface for us to call. If we don’t turn on fault tolerance we can extract the authentication object JwtAuthenticationToken from the Spring Security provided SecurityContext object to the resource server which contains the JWT token and then we can implement Feign’s interceptor interface RequestInterceptor to place the token in the request header, with the following pseudo-code.
|
|
This wouldn’t be a problem if we didn’t turn on fault tolerance. Fault tolerance is basically turned on to prevent an avalanche of services in the call chain. At this point, we can’t get Authentication from SecurityContextHolder. This is because the Feign call is then made in another sub-thread opened under the caller’s call thread. Since the fault-tolerant component I’m using is Resilience4J , the source code for the corresponding thread is in Resilience4JCircuitBreaker.
|
|
SecurityContextHolder saves information by default through the ThreadLocal implementation, which we all know is not cross-threaded, and Feign’s interceptor happens to be in the child thread at this time, so Feign with fault tolerance (circuitBreaker) turned on can not be directly token relay .
The fault-tolerant components are Hystrix (obsolete), Resilience4J, and Ali’s Sentinel, which may have slightly different mechanisms.
Implementing Token Relay
Although I can’t implement token relay directly, I found some information from it. In the processor FeignCircuitBreakerInvocationHandler of the Feign interface proxy, I found the following code.
|
|
This is the execution code of the Feign proxy class and we can see that before the execution :
|
|
Here is to get information about the request in the calling thread, including ServletHttpRequest, ServletHttpResponse and other information. Immediately after the lambda code to Setter this information again into.
|
|
If this were an operation performed in one thread, it would be redundant. In fact the Supplier return value is executed in another thread. The purpose of this is to preserve some request metadata across threads.
InheritableThreadLocal
How does the RequestContextHolder pass data across threads?
|
|
The RequestContextHolder maintains two containers, a ThreadLocal that cannot cross threads and a NamedInheritableThreadLocal that implements the InheritableThreadLocal.
The InheritableThreadLocal is able to pass data from the parent thread to the child thread, based on this principle the RequestContextHolder brings the caller’s request information into the child thread, and with the help of this principle the token relay can be implemented.
Implementing token relay
Changed the initial Feign interceptor code a bit to implement the token relay
|
|
This way when you call FooClient.bar(), the resource server (OAuth2 Resource Server) in foo-service can also get the caller’s token and thus the user’s information to handle resource permissions and operations.
Don’t forget to inject this interceptor into Spring IoC.
Summary
Microservice token relaying is very important to ensure that user state is passed through the invocation link. And this issue is also one of the hard parts of microservices. Today we have implemented token relaying with the help of Feign and some features of ThreadLocal.
For your reference.
Reference https://felord.cn/feign-token-relay.html