如何实现双Token无感刷新

为什么要用双Token无感刷新,它解决了什么问题?

        为了保证安全性,后端设置的Token不可能长期有效,过了一段时间Token就会失效。而发送网络请求的过程又是需要携带Token的,一旦Token失效,用户就要重新登陆,这样用户可能需要频繁登录,体验不好。为了解决这个问题,采取双Token(Access_Token,Refresh_Token)无感刷新,用户完全体会不到Token的变化,但实际上,Token已经刷新了。

这两个Token都是干什么的?具体过程是怎样的?

         前置条件:

                后端提供一个刷新Token的接口,假设是A接口。

两个Token的作用:

        Access_Token:用于鉴定用户身份,即每次发送网络请求都需要携带这个Access_Token

        Refresh_Token:用于刷新Access_Token,即调用A接口需要携带Refresh_Token,  用它换得最新的Access_Token      

        过程:

        1.用户登录客户端之后,接收后端发送的两个Token,前端把它们存在localStorage或vuex中。

        2.Access_Token未过期时,发送网络请求携带Access_Token即可

        3.Access_Token过期后,前端携带Refresh_Token调用A接口得到新的Access_Token,把新的Access_Token替换旧的Access_Token存储起来。

具体如何实现?

        首先先明确一点,这个无感刷新的逻辑要写在axios的响应拦截器里面。

        说明:

        isRefreshing用于标记是否正在调用tokenRefreshAPI,相当于一把锁

        requests队列用于存储tokenRefreshAPI响应期间进入的promise对象。

var isRefreshing = false,
//重试队列
requests = [],

说明:

        service是自己配置的axios,在axios里面配置一些基本设置,比如baseURL,timeout,headers的Authorization(一般是"Bearer"+Access_Token)

 service.interceptors.response.use(
    res => {
      //accesstoken超时
      if (res.data.result_status === 30002) {
        //记录当前res
        let response = res;
        if (!isRefreshing) {
          isRefreshing = true;
          return tokenRefreshAPI({
            token: JSON.parse(window.localStorage.token)
          }).then((res) => {
            //refreshToken没过期,刷新成功
            console.log('tokenRefreshAPI', res.data);
            if (res.data.result_status === 0) {
              console.log('token刷新成功', res.data);
              //重新设置token
              window.localStorage.setItem('token', JSON.stringify(res.data.token));
              //执行失效的函数
              requests.forEach((cb) => cb());
              requests = []; // 重新请求完清空
              return service(response.config);
            } else if (res.data.result_status === 30011) {
              console.log('refreshToken过期,请重新登录');
              window.localStorage.clear();
              router.push('/login');
            }
          }).finally(() => {
            isRefreshing = false;
          });
        } else {
          console.log('token过期,剩余请求存入队列', axiosConfig.url);
          // 返回未执行 resolve 的 Promise
          return new Promise(resolve => {
            // 用函数形式将 resolve 存入,等待刷新后再执行
            requests.push(() => {
              resolve(service(axiosConfig));
            });
          });
        }
      }
      return res;
    })

注意:

        在Access_Token过期后,可能会短时间发送很多个网络请求,这些网络请求拦截器全都会请求刷新Token,这样显然是不合理的。其实只要刷新一次就够了,所以给刷新Token这步操作加一个锁,这也就是为什么要设置isRefreshing的原因。

        在请求刷新Token的响应时间内,可能会有多个网络请求到达,我们又暂时没办法处理这些网络请求,所以我们先把这些网络请求promise对象存储到队列requests里面,等到刷新好Token之后再依次处理这些promise对象。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值