查看原文
其他

实战!openFeign如何实现全链路JWT令牌信息不丢失?

不才陈某 码猿技术专栏 2023-02-06

大家好,我是不才陈某~

这是《Spring Cloud 进阶》20篇文章,往期文章如下:

今天这篇文章介绍一下JWT令牌如何在微服务链路中保证信息不丢失?官方称为令牌中继

什么是令牌中继?

令牌中继通俗的讲则是让令牌在微服务链路调用中传递下去,保证各个微服务能够获取令牌中的用户信息。

以下订单的例子来说,如下图:

下单流程

客户端携带令牌请求网关,网关鉴权成功后会将令牌中的用户信息解析出来放在请求头中下发给订单服务,同样的,订单服务需要将用户信息传递给账户服务获取该用户的账户信息。

那么问题来了?如何保证网关服务->订单服务->账户服务这条链路中的用户信息传递下去是个痛点

解决方案

令牌在openFeign调用过程中是不能自动中继的,因此必须手动的将令牌信息传递下去。

注意:openFeign在开启熔断降级后内部调用开启了子线程,因此传统的方案直接在RequestInterceptor中设置是不可行的。

那么如何保证子线程也能获取请求头中的用户信息呢?

答案是:RequestContextHolder这个神器。

RequestContextHolder内部通过InheritableThreadLocal实现子线程共享信息。

FeignCircuitBreakerInvocationHandler这个类中也是有如下一行代码:

RequestContextHolder.setRequestAttributes(requestAttributes);

正是使用RequestContextHolder将request的信息保存在其中,因此实现令牌中继只需要读取RequestContextHolder的信息即可。

详细代码如下:

/**
 * @author 公众号:码猿技术专栏
 * 用于实现令牌信息中继
 */

@Component
public class FeignRequestInterceptor implements RequestInterceptor {
    
@Override
    
public void apply(RequestTemplate template) {
        
//从RequestContextHolder中获取HttpServletRequest
        HttpServletRequest httpServletRequest = RequestContextUtils.getRequest();
        
//获取RequestContextHolder中的信息
        Map<String, String> headers = getHeaders(httpServletRequest);
        
//放入feign的RequestTemplate中
        
for (Map.Entry<String, String> entry : headers.entrySet()) {
            template.header(entry.getKey(), entry.getValue());
        }
    }

    
/**
     * 获取原请求头
     */

    
private Map<String, String> getHeaders(HttpServletRequest request) {
        Map<String, String> map = 
new LinkedHashMap<>();
        Enumeration<String> enumeration = request.getHeaderNames();
        
if (enumeration != null) {
            
while (enumeration.hasMoreElements()) {
                String key = enumeration.nextElement();
                String value = request.getHeader(key);
                map.put(key, value);
            }
        }
        
return map;
    }
}

源码目录如下图:

源码已经上传GitHub,关注公众号:码猿技术专栏,回复关键词:9529 获取!

最后说一句(别白嫖,求关注)

陈某每一篇文章都是精心输出,已经写了3个专栏,整理成PDF,获取方式如下:

  1. 《Spring Cloud 进阶》PDF:关注公众号:【码猿技术专栏】回复关键词 Spring Cloud 进阶 获取!
  2. 《Spring Boot 进阶》PDF:关注公众号:【码猿技术专栏】回复关键词 Spring Boot进阶 获取!
  3. 《Mybatis 进阶》PDF:关注公众号:【码猿技术专栏】回复关键词 Mybatis 进阶 获取!

如果这篇文章对你有所帮助,或者有所启发的话,帮忙点赞在看转发收藏,你的支持就是我坚持下去的最大动力!

关注公众号:【码猿技术专栏】,公众号内有超赞的粉丝福利,回复:加群,可以加入技术讨论群,和大家一起讨论技术,吹牛逼!

求点赞、在看、分享三连

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存