vue axios中使用accesstoken、refreshtoken实现接口保活的方案

vue axios中使用access_token、refresh_token实现接口保活的方案

回想起在做智能应用平台移动端时,通过jwt(JSON WEB TOKEN)的方式实现身份认证。简单来说就是一个加密令牌,服务端能通过算法加密用户信息并随着请求和相应传送,进而能让服务端知道登录的是谁,他有没有权限进入我的服务器获取信息。jwt有过期时间,过了这个时间,客户单再次向服务端发送接口请求的时候就需要进行重新认证,即重新登录。假如用户正在操作,这时候再次请求后端服务的时候就会突然跳到登录界面,严重影响了用户体验,智能应用平台jwt的失效时间是15min,先别说用户会有怎样的体验,就是在开发过程中,也需要反复请求新的token,简直要崩溃!还记得当时我们采用的方案是每隔一定时间,就静默地调用token请求接口,替换旧的token,这样避免用户在操作的过程中不会突然跳到登录界面的不好体验。但是,这样一来,就使得token失去了它应有的安全机制。基于当时技术的局限,只能采用这种方式。

最近看到了通过access_token、refresh_token实现token失效无痕刷新的技术博客,让我的思绪又回到了两年前那个激荡的日子。采用access_token过期,refresh_token进行刷新,很好的兼顾了用户体验和安全性的要求。基本思路如下:

  • access_token为登录后获得的请求凭证,有效期较短,例如智能应用平台为15min,使用expires(过期时间)与当前时间戳进行比较,判断是否过期,若过期,需要使用refresh_token重新获取;
  • refresh_token是用来刷新access_token的凭证,作为获取当前access_token的参数,换取新一轮的access_token,有效期一般为两倍的access_token,若过期,则需要重新登录;
  • expires是当前access_token过期时刻的时间戳,一般会在距离过期前一定时间重新请求一一轮的access_token。

刷新access_token的机制

所谓的刷新access_token就是在用户登录后会返回access_token和refresh_token两个字段,用户在访问需要权限的接口时需要带access_token字段才能进行访问,也会返回access_token的过期时间,客户端在发起每次请求时都需要检测access_token是否即将过期,如果过期了,当用户访问权限接口时就会报错而退出。为了提高用户使用时的体验感,当access_token即将过期时,客户端需要用refresh_token主要发起刷新access_token的接口来获取新的access_token。刷新成功后会返回新的access_token和refresh_token,当然了,如果refresh_token也过期了的话就只能跳到登录界面了。

刷新access_token的实现

基于axios实现该方案,axios有请求拦截器和响应拦截器,可以在请求和响应之前对请求做一些处理来实现该方案。这里有两种场景需要讨论,第一种场景是一个页面可能存在多个请求,若刚好打开页面的时候access_token过期就会有多个刷新access_token的请求;第二种场景是,一个接口刷新access_token,新的access_token还没来得及更新,另外的接口就用老的access_token去请求数据也会出错。所以,采用以下方式:

  • 当打开页面时access_token已经过期,这个页面所有请求通过数组的方式进行保存;
  • 设置一个标志判断是否正在刷新,由一个接口去请求刷新access_token,待access_token更新后,再让其他请求用心的access_token重新请求数据;

关键代码

js 复制代码
/** 是否正在刷新的标志 */
isRefreshing = false;

/** 存储请求的数组 */
let subscribers = [];

/** 将请求放入数组中 */
const addSubscribers = (cb) => subscribers.push(cb);

/** 带新的token并执行 */
const doSubscribers = (cb) => subscribers.map((cb) => cb(token));

/** axios拦截器 */
req.interceptors.request.use((request) => {
  /** 判断是否登录 */
  if (token) {
    request.headers.token = token;
    /** 判断是否即将过期,并且不是刷新token的接口refreshToken,这里是伪代码 */
    if (isExpired() && request.url !== API.refreshToken) {
      /** 先判断当前是否正在刷新,如果不是,将刷新标志置为true并请求心的token,如果是,将请求存到数组里 */
      if (!isRefreshing) {
        isRefreshing = true;
        refreshtoken().then((res) => {
          /** 新的token替换旧的token */
          request.headers.token = res.data.token;
          /** 跟新新token和refresh_token以及相关业务逻辑,这里是伪代码 */
          setData();
          /** 执行数组里的请求 */
          doSubscribers();
        })
     }
     let retry = new Promise((resolve, reject) => {
       addSubscribers((token) => {
       request.headers.token = token;
       resolve(request)
     });
  });
  return retry;
} else {
  return request;
}
} else {
  return request;
  }
}, (error) => {
  return promise.reject(error);
});

总结

使用access_token、refresh_token实现接口保活的方案不仅能够用于移动客户端,而且还能应用于采用jwt方案的鉴权系统,该方案在充分发挥jwt安全校验的基础上,还能极大的提高用户体验,并且,该方案中运用的请求队列的编程思想较为先进,对后续的开发有很好的借鉴和帮助作用。

接口数据测试

参数名称 参数位置 类型 必填 描述 示例
access_token Head String true 用户凭证,获取方式参考文档(help.hikyun.com/document/16... eyJ···9.eyJ···0.3cA···g
相关推荐
卸任3 小时前
Vibe coding工具使用心得
前端·ai编程
brien94 小时前
为什么模型标称 1M,Google Antigravity 聊到 256K 却突然失忆?我们给它做了个原生行内监控圆环
前端
修炼的dance4 小时前
录屏关键帧间隔多少合适?六档实测,2秒到10秒小了75.6%
前端
Lank_M4 小时前
关键帧从1秒拉到10秒,录屏小87.3%,摄像头小10.8%
前端
补码缩写4 小时前
用 ffprobe 拆录屏,八成字节在 29 个关键帧上
前端
百思不得小李4 小时前
一个复杂的动态表单是如何实现的
前端·设计模式
陈随易4 小时前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
风骏时光牛马5 小时前
前沿视界
前端
kyriewen5 小时前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员
陈随易5 小时前
3000 万人在用的翻译插件,重写一遍就是一门生意
前端·后端·程序员