SpringCloud Alibaba 微服务番外篇二 - Feign 传递 Access_Token

概述

还记得我们之前创建订单的流程吗?

通过网关调用 order-service 的 create 方法,然后 order-service 再通过 feign 调用 account-service 的 reduce 和 product-service 的 deduct 方法进行业务逻辑处理。
image.png

当我们项目整合好 oauth2 后再来调用之前的方法发现调用异常,查看后端日志发现如下的错误信息:

org.springframework.security.authentication.InsufficientAuthenticationException: Full authentication is required to access this resource

Request processing failed; nested exception is feign.FeignException$Unauthorized: status 401 reading AccountFeign#reduce(String,BigDecimal)

错误信息告诉我们是接口未授权导致访问异常,实际上我们已经将 access_token 放在了 header 上,如下:
image.png

最后通过对自定义异常类进行跟踪发现是 access_token 经过 order-service 访问 account-service 时丢失了,获取的 accessToken 为 null。
image.png

本节主要是来解决使用 feign 调用时 access_token 丢失的问题。

代码示例

Feign 支持请求拦截器,在发送请求前,可以对发送的模板进行操作,例如设置请求头等属性,自定请求拦截器只需要实现 RequestInterceptor 接口,该接口的方法有 RequestTemplate 类型的参数,我们可以根据实际情况对请求的信息进行调整。

public interface RequestInterceptor {
    void apply(RequestTemplate var1);
}

我们要实现的功能很简单,就是取出原来的请求头,再将其传递给下游服务,在 order-service 中建立 FeignRequestInterceptor 并给其添加 @Configuration 注解,代码如下:

/**
 * Description:
 * 微服务之间feign调用请求头丢失的问题
 * @author javadaily
 * @date 2020/02/24 9:28
 */
@Configuration
@Slf4j
public class FeignRequestInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        HttpServletRequest httpServletRequest =   getHttpServletRequest();
        if(httpServletRequest!=null){
            Map<String, String> headers = getHeaders(httpServletRequest);
            // 传递所有请求头,防止部分丢失
            //此处也可以只传递认证的header
            //requestTemplate.header("Authorization", request.getHeader("Authorization"));
            for (Map.Entry<String, String> entry : headers.entrySet()) {
                template.header(entry.getKey(), entry.getValue());
            }
            log.debug("FeignRequestInterceptor:{}", template.toString());
        }
    }


    private HttpServletRequest getHttpServletRequest() {
        try {
            return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取原请求头
     */
    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;
    }
}

完成配置后重启服务器,再次调用 create 方法,正常返回响应结果。
image.png

  • Spring

    Spring 是一个开源框架,是于 2003 年兴起的一个轻量级的 Java 开发框架,由 Rod Johnson 在其著作《Expert One-On-One J2EE Development and Design》中阐述的部分理念和原型衍生而来。它是为了解决企业应用开发的复杂性而创建的。框架的主要优势之一就是其分层架构,分层架构允许使用者选择使用哪一个组件,同时为 JavaEE 应用程序开发提供集成的框架。

    732 引用 • 1290 回帖 • 711 关注
  • 架构

    我们平时所说的“架构”主要是指软件架构,这是有关软件整体结构与组件的抽象描述,用于指导软件系统各个方面的设计。另外还有“业务架构”、“网络架构”、“硬件架构”等细分领域。

    96 引用 • 390 回帖 • 1 关注
  • 微服务

    微服务架构是一种架构模式,它提倡将单一应用划分成一组小的服务。服务之间互相协调,互相配合,为用户提供最终价值。每个服务运行在独立的进程中。服务于服务之间才用轻量级的通信机制互相沟通。每个服务都围绕着具体业务构建,能够被独立的部署。

    64 引用 • 128 回帖 • 11 关注
回帖
请输入回帖内容...