Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

请求配置JWT,无感刷新token #47

Open
jynba opened this issue May 13, 2024 · 0 comments
Open

请求配置JWT,无感刷新token #47

jynba opened this issue May 13, 2024 · 0 comments

Comments

@jynba
Copy link
Owner

jynba commented May 13, 2024

请求配置JWT,无感刷新token

jwt大白话:登录时后端会返回一个token,前端需要把这个token带在此后的每个请求的请求头(Authorization: Bearer enxxxxxxxx),当携带的token不合法时,后端就会返回403,前端接收后跳转重新请求登录。
其中:怎么样就算token不合法呢?token中会包含后端对时间base64加密,且后端设置了token过期时间,当前端传过去的token时间过期或者格式不对,也属于不合法。
这样一来在用户使用体验上会有一个问题,用户用着用着就需要重新登录,体验不好。因此,我们可以考虑使用无感刷新token来避免跳转登录。
前提:1. 前后端预定好token过期时间 (或后端返回过期时间)

  • 方法一:在请求发起前拦截每个请求,判断token的有效时间是否已经过期,若已过期,则将请求挂起,先刷新token后再继续请求。(废弃!!!)
  • 缺点:需要返回时间,判断是否过期
  • 方法二:不在请求前拦截,而是拦截返回后的数据。先发起请求,接口返回过期后,先刷新token,再进行一次重试。
  • 缺点:需要请求两次

代码实现:(方法1)(废弃!!!)

  1. 在http请求中 拦截除了登录请求外的其他请求,在请求前先解码token,获取时间,判断时间是否过期,若过期则将请求挂起,注意要将此时的请求存进队列中,通过设置一个flag来判断是否正在刷新token,等待token刷新后在重新请求队列。
    有坑:注意时间不能在前端获取,小程序中使用new Date获取到的时间是手机的系统时间,存在误差
  private async mergeDefaultHeader<U>(config: IRequestType<U>) {
    //过滤白名单
    if (!filterUrl(config.url)) {
      const token: string = uni.getStorageSync(TOKEN);
      if (token) {
        // 判断token是否过期
        const epired_in = JSON.parse(base64.decode(token.split('.')[1])).exp;
        const now = new Date().getTime();
        console.log(new Date(epired_in * 1000), new Date());

        if (epired_in * 1000 < now + TOKEN_EXPIRE) {
          this.refreshToken(config, () => {});
          return false; //将该请求挂起
        }
      }
      config.header.Authorization = `Bearer ${token}`;
      console.log('config.header.Authorization ', config.header.Authorization);
    }
    return Object.assign({}, this.header, config.header);
  }

  private refreshToken<T, U>(config: IRequestType<U>, resolve: any) {
    this.waitRequestQueue.push(() => {
      resolve(this.request(config));
    });
    if (!refreshing) {
      refreshing = true;
      login()
        .then(() => {
          // 重新请求队列
          this.waitRequestQueue.map((MT) => {
            MT();
          });
          this.waitRequestQueue = []; //清空队列
        })
        .finally(() => {
          //解除正在刷新
          refreshing = false;
        });
    }
  }

(方法二):先发起请求,接口返回过期后,先刷新token,再进行一次重试。根据401状态码来重试

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant