> 文档中心 > feign在调用时token丢失问题

feign在调用时token丢失问题

目录

1.问题描述:

2.问题排查过程: 

3.解决方法:

(1)全局配置:

(2)拿传入的token通过Bean的方式注入

(3)实现RequestInterceptor方法




1.问题描述:

我在使用spring cloud微服务架构的时候,通常是通过feign实现不同的服务之间的调用。开始使用的时候,都是两个服务之间的调用,例如A调用B。B调用C。在加入jwt的时候,这种两个服务之间的调用,token能够传过去,但是如果A--->B--->C A服务通过调用B之后再调用C服务。我们就会发现问题


明明传了token了,但是显示未登录,???什么鬼

2.问题排查过程: 

 后来通过断点调试,发现当第二次进行feign请求的时候,header中没有了token。再进行跟入发现会有一个RequestInterceptor

 

  

这里有一个拦截器RequestInterceptor

 看到了问题的解决方法。


3.解决方法:

(1)全局配置:

如果项目中用的是 HttpClient 或者 RestTemplate 之类的调用接口,则可以在调用之前申请 Token,然后将其塞到请求头中。

在 Spring Cloud 中消费接口肯定是用 Feign 来做的,这意味着我们需要对 Feign 进行改造,需要往请求头中塞上我们申请好的 Token。

1. 定义请求拦截器

对于 Token 的传递操作,最好在框架层面进行封装,对使用者透明,这样不影响业务代码,但要求通用性一定要强。我们可以定义一个 Feign 的请求拦截器来统一添加请求头信息,代码如下所示。

/*** Feign 请求拦截器**/public class FeignBasicAuthRequestInterceptor implements RequestInterceptor {    public FeignBasicAuthRequestInterceptor() {    }    @Override    public void apply(RequestTemplate template) { template.header("Authorization", System.getProperty("fangjia.auth.token"));    }}

 上面的准备好之后,我们只需要在调用业务接口之前先调用认证接口,然后将获取到的 Token 设置到环境变量中,通过 System.setProperty("fangjia.auth.token",token) 设置值,或者通过定时任务刷新设置。

这样我们就可以通过 System.setProperty("fangjia.auth.token",token) 获取到需要传递的 Token。 

(2)拿传入的token通过Bean的方式注入

这里只需要注入一个RequestInterceptor就行了

@Configuration@Datapublic class FeignRequestInterceptor{    /**     * feign调用丢失token解决方式,新增拦截器     * @return     */    @Bean    public RequestInterceptor requestInterceptor(){ return template -> {     ServletRequestAttributes attributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();     if(attributes!=null){  HttpServletRequest httpServletRequest = attributes.getRequest();  if(httpServletRequest == null){      return;  }  String token = httpServletRequest.getHeader("token");  template.header("token",token);     } };    }}

(3)实现RequestInterceptor方法

import feign.RequestInterceptor;import feign.RequestTemplate;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes; import javax.servlet.http.HttpServletRequest;@Configurationpublic class FeignConfig implements RequestInterceptor {    @Override    public void apply(RequestTemplate requestTemplate) { ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); //添加token requestTemplate.header("token", request.getHeader("token"));    }}

经过调试发现这些方法都能将token传递下去。最后一种方法更简单。

在进行断点调试,我们就会发现这时headers就会有token了。ok问题解决

以后遇到这种问题要通过断点调试一点一点的跟进,由表及里一步一步的解决问题。

后来在查询的时候,看到了一篇文章也是介绍这个的,但是写引入hytrix的问题

补充:如果引入hytrix可能会有问题。

注意!!!,这里会有个异常,获取到的request会是null。原因是hytrix隔离策略是thread,无法读到 threadLocal变量。

解决办法!!更改策略

在配置文件中新增如下配置,即可解决!

# 更换hystrix策略,解决无法传递threadLocal变量问题hystrix:    command: default:     execution:  isolation:      strategy: SEMAPHORE