在构建微系统的时候,系统由一个微服务A,一个微服务B构成,登录使用的是springsecurity+jwt进行认证,现在登录写在服务A中,在调用服务B时候,报错401了。
test接口为服务A中的调用服务B的接口,在登录状态下,调用test接口,报错401了
单独调用服务B的接口,没有问题
先贴原因:
原因:Feign发起远程调用与微服务A调用Feign去发起请求的线程不一样,微服务A调用feign的时候是线程1,通过Feign远程调用微服务B的是feign对象,Feign对象的底层是使用restTemplate对象去调用微服务B,和线程1的request对象没有关系,所以restTemplate对象不含token,没有token就相当于没有用户名和密码,所以就出现401异常。
解决方法:
解决方法:需要使用一个拦截器组件,将request对象中的请求头放到restTemplate对象里,再进行远程调用,就不会出现401异常
拦截器组件的作用:微服务的所有Feign调用在发起HTTP请求之前,先进入这个拦截器。然后再发起调用
在服务A中定义拦截器Interceptor:
@Component
public class Interceptor implements RequestInterceptor {
/**
* 拦截器方法
*
* @param requestTemplate
*/
@Override
public void apply(RequestTemplate requestTemplate) {
/*
* 获取原线程的request对象的请求头中的token
* RequestContextHolder.getRequestAttributes():获取request原始的请求头对象
* 接口类RequestAttributes不能使用,所以强转为ServletRequestAttributes类型
*/
ServletRequestAttributes servletRequestAttributes =
(ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
//防止空指针
if (servletRequestAttributes==null) {
return;
}
//获取原Request对象
HttpServletRequest request = servletRequestAttributes.getRequest();
//把原request的请求头的所有参数都拿出来
Enumeration<String> headerNames = request.getHeaderNames();
while (headerNames.hasMoreElements()) {
//获取每个请求头参数的名字
String name = headerNames.nextElement();
//获取值
String value = request.getHeader(name);
//放到feign调用对象的request中去
requestTemplate.header(name,value);
}
}
}
重启服务,在A中调用B:成功调用到了
参考链接:
Feign发起远程调用出现401异常(没有访问权限)