自定义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 方法抽取携带在请求中的令牌信息。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。