需求场景
在使用Spring Security Oauth2
时,通过消息头中的Authorization Bearer toeknXXXX
对令牌进行校验,如果失败,是会拒绝访问的。
那么在使用Feign
进行调用时,就会出现问题,因为Feign
发送请求时,是没有传递认证消息头的。
解决方案
实现RequestInterceptor
,获取原本请求中的认证消息头,然后添加到请求模板中。
@Component
public class Oauth2TokenRequestInterceptor implements RequestInterceptor {
@Override
public void apply(RequestTemplate requestTemplate) {
// 获取请求中的消息头
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String requestHeader = request.getHeader(HttpHeaders.AUTHORIZATION);
if (StringUtils.isNotBlank(requestHeader) && requestHeader.startsWith("Bearer ")) {
// 将消息头塞入到请求模板中
requestTemplate.header(HttpHeaders.AUTHORIZATION, requestHeader);
}
}
}
测试,可以看到Feign
请求成功传递了消息头。
源码分析
在创建SynchronousMethodHandler
时,可以看到,会将从配置或者IOC中查找请求拦截器,并赋值给自己。
在通过请求模板创建请求对象时,会迭代拦截器,并调用其 apply
,将消息头放入到请求模板中。
最终在发送请求时,请求头中就包含拦截器设置的消息头了。
FeignClient 注解中配置请求拦截器
也可以直接在@FeignClient
注解中,直接添加拦截器,它只作用于当前Feign 客户端,比如:
@FeignClient(name = "order-service",configuration = {
BBBRequestInterceptor.class})
此时,全局的、客户端自己的,会在请求时,加入到请求拦截器链中,循环执行。