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