当前位置: 首页 > article >正文

定时任务调用OpenFegin无token认证异常

问题

定时任务job中有调用其他服务,由于不是通过接口进来的,属于是未登录状态,如果这时候调用openfegin的接口,这个请求是没有token的,会抛出没有权限的异常。

分析

项目中OpenFegin默认是通过RequestContextHolder获取ServletRequestAttributes,获取HttpServletRequest得到Header中的token的。

如果是网络请求接口,因为网关是同一个服务间token可以通用,就可以调用其他服务。但是如果通过定时任务执行这个方法,因为没有经过Servlet,RequestContextHolder中没有这个线程对应的HttpServletRequest,因此调用OpenFegin的时候就会报[401]unauthorized异常

-------------RequestContextHolder.java
RequestAttributes.getRequestAttributes();
@Nullable
public static RequestAttributes getRequestAttributes() {
    RequestAttributes attributes = requestAttributesHolder.get();
    if (attributes == null) {
        attributes = inheritableRequestAttributesHolder.get();
    }
    return attributes;
}

--------------ThreadLocal<T>.java
 requestAttributesHolder.get();
inheritableRequestAttributesHolder.get();
public T get() {
    Thread t = Thread.currentThread();
    ThreadLocalMap map = getMap(t);
    if (map != null) {
        ThreadLocalMap.Entry e = map.getEntry(this);
        if (e != null) {
            @SuppressWarnings("unchecked")
            T result = (T)e.value;
            return result;
        }
    }
    return setInitialValue();
}

要解决这个问题,首先想到的是既然RequestContextHolder没有当前线程的HttpServletRequest那就添加一个,但是创建一个HttpServletRequest对象过于复杂,也不能保证后续不出问题,所以这个方法不太好。于是就想到了在OpenFegin传递token的时候下手,也就是在OpenFegin的拦截器中处理。如果不能获取到当前线程的HttpServletRequest,那就执行模拟登录,生成一个token,然后将这个token放入到RequestTemplate中,这样就能实现远程的认证调用。

@Configuration
public class FeignConfig implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate requestTemplate) {
        if (!support(requestTemplate)) {
            return;
        }
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = null;
        if (attributes != null) {
            request = attributes.getRequest();
            //添加token 不传递
            requestTemplate.header(HttpHeaders.AUTHORIZATION, request.getHeader(HttpHeaders.AUTHORIZATION));
        } else {
            //业务代码,模拟登录获取token
            //添加token
            requestTemplate.header(HttpHeaders.AUTHORIZATION, token);
        }
    }

    public boolean support(RequestTemplate requestTemplate) {
        //获取openfegin接口是否标准不需要token的注解
        MethodMetadata methodMetadata = requestTemplate.methodMetadata();
        Method method = methodMetadata.method();
        NotTransmitToken[] annotations = method.getDeclaredAnnotationsByType(NotTransmitToken.class);
        return !(annotations.length > 0);
    }
}

由于这里登录是写死的,所以需要一个特殊的用户,用户名和密码得固定住,或者也可以生成一个永不过期的token。这两种方法都有一定安全风险,需要进一步加密或者优化来保证权限不泄露。


http://www.kler.cn/a/305292.html

相关文章:

  • 【Linux】TCP原理
  • 【含开题报告+文档+PPT+源码】基于Spring Boot智能综合交通出行管理平台的设计与实现
  • jenkins提交gitee后自动部署
  • ubuntu cmake CPack将第三方库进行打包
  • 【贪心算法】——力扣763. 划分字母区间
  • Java-Redisson分布式锁+自定义注解+AOP的方式来实现后台防止重复请求扩展
  • LAMP+WordPress
  • 服务器运维面试题4
  • 【SpringBoot】调度和执行定时任务--Quartz(超详细)
  • Ubuntu 22.04.5 LTS 发布下载 - 现代化的企业与开源 Linux
  • 力扣移除元素(力扣题26)(插空找空位java)
  • Linux上使用touch修改文件时间属性的限制
  • 如何打造智能、高效、安全的智慧实验室
  • 【React源码解析】深入理解react时间切片和fiber架构
  • C++——智能指针
  • CH1-1 引论
  • Rust:Result 和 Error
  • 职场 Death Note
  • Uniapp + Vue3 + Vite +Uview + Pinia 实现提交订单以及支付功能(最新附源码保姆级)
  • MATLAB中who的用法
  • flink增量检查点启动恢复的时间是很久的,业务上不能接受,怎么处理
  • MySQL索引-聚簇索引和非聚簇索引
  • 【Python机器学习】循环神经网络(RNN)——传递数据并训练
  • flask中安全策略简要说明
  • 景联文科技:专业扫地机器人数据采集标注服务
  • C/C++动态库函数导出 windows