自定义Feign拦截器,解决微服务之间Feign调用请求头丢失问题
在微服务开发过程中,安全方面使用的是Spring Security OAuth2.0令牌认证,在进行服务与服务之间调用时,使用的Feign客户端,如果不通过Feign拦截器来添加请求头信息。下游服务是接收不到认证过的token令牌,无法进行身份验证。

定义Feign拦截器,实现 RequestInterceptor 接口

@Slf4j
public class FeignRequestInterceptor implements RequestInterceptor {

/**
 * 微服务之间传递的唯一标识
 */
public static final String X_REQUEST_ID = "X-Request-Id";

@Override
public void apply(RequestTemplate template) {

    HttpServletRequest httpServletRequest = getHttpServletRequest();

    if (httpServletRequest != null) {
        //获取头信息
        Map<String, String> headers = getHeaders(httpServletRequest);
        // 传递所有请求头,防止部分丢失
        Iterator<Map.Entry<String, String>> iterator = headers.entrySet().iterator();

        //将请求的头信息放入到RequestTemplate 的头信息中,当使用RequestTemplate发起请求时会自动添加头信息
        while (iterator.hasNext()) {
            Map.Entry<String, String> entry = iterator.next();
            template.header(entry.getKey(), entry.getValue());
        }
        // 微服务之间传递的唯一标识,区分大小写所以通过httpServletRequest获取
        if (httpServletRequest.getHeader(X_REQUEST_ID) == null) {
            String sid = String.valueOf(UUID.randomUUID());
            template.header(X_REQUEST_ID, sid);
        }
        log.debug("FeignRequestInterceptor:{}", template.toString());
    }
}

/**
 * RequestContextHolder 中获取 HttpServletRequest对象
 *
 * @return
 */
private HttpServletRequest getHttpServletRequest() {
    try {
        return ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
    } catch (Exception e) {
        return null;
    }
}

/**
 * 获取头信息
 *
 * @param request
 * @return
 */
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;
}

}
配置Bean

@Bean

@ConditionalOnMissingBean(FeignRequestInterceptor.class)
public RequestInterceptor feignRequestInterceptor() {

    FeignRequestInterceptor interceptor = new FeignRequestInterceptor();
    log.info("FeignRequestInterceptor [{}]", interceptor);
    return interceptor;
}

在每次进行调用时,会经过 OAuth2AuthenticationProcessingFilter 过滤器的 doFilter方法进行token验证,通过 tokenExtract 的 extract 方法抽取携带在请求中的令牌信息。


棘丶
12 声望1 粉丝

下一篇 »
异步调用