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

解决方法:

全局配置:

如果项目中用的是 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) 设置值,或者通过定时任务刷新设置。

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

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

@Configuration
@Data
public 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;
@Configuration
public 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"));
    }
}

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

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

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

 @Bean
      public RequestInterceptor requestInterceptor(){
          return template -> {
              ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
              if (attributes != null) {
                  HttpServletRequest request = attributes.getRequest();
                  if (null == request){
                      return ;
                  }
                  template.header("satoken", attributes.getRequest().getHeader("satoken"));
              }else {
                  log.info("空异常");
              }
              log.info("feign拦截器");
          };
      }