管理系统项目,基于vue+axios,使用axios拦截器实现自动刷新token机制

整个项目的首次登录会获取到用户的token,refreshToken,expires_in

  • token为本次登录的请求凭证,有效期较短,使用expires_in与当前时间戳进行比较,判断是否过期,一般为两个小时,若过期,需要使用refreshToken重新换取
  • refreshToken是用来刷新token的凭证,作为获取当前token接口的参数,换取新一轮的token,有效期较长,一般为半个月,若过期,需要重新登录获取
  • expires_in是当前token过期时刻的时间戳,一般会在距离过期前10分钟,重新请求新一轮的token

嘿嘿~~~~~~~废话不多说,贴一段代码!(本人亲测有效!)

/* 是否有请求正在刷新token */
window.isRefreshing = false
/* 被挂起的请求数组 */
let refreshSubscribers = []

/* push所有请求到数组中 */
function subscribeTokenRefresh(cb) {
  refreshSubscribers.push(cb)
}

/* 刷新请求(refreshSubscribers数组中的请求得到新的token之后会自执行,用新的token去请求数据) */
function onRrefreshed(token) {
  refreshSubscribers.map(cb => cb(token))
}

const fetch = axios.create({
  baseURL: '',
  timeout: '30000'
})

function computedTime() {
  let r = getRefresh();
  if (!r || !r.expires_in) return false;
  let currentTime = Date.parse(new Date()) / 1000;
  let expiresTime = r.expires_in;
  // 600秒后即将过期,true则不需要刷新
  return expiresTime - currentTime <= 600
}
fetch.interceptors.request.use(async (config) => {
  if (config.url !== '/oauth/token') {//获取token的接口不进行拦截
    getToken() && (config.headers.Authorization = getToken());
    if (computedTime()) {
      if (!window.isRefreshing) {
        window.isRefreshing = true;
        let r = getRefresh();
        if (!r) return;
        let refreshData = {
          grant_type: 'refresh_token',
          client_id: r.client_id,
          client_secret: r.client_secret,
          refresh_token: r.refresh_token
        }
        getTokens(refreshData).then((data) => {
          window.isRefreshing = false;
          let rData = {
            client_id: r.client_id,
            client_secret: r.client_secret,
            expires_in: (Date.parse(new Date()) / 1000 + data.expires_in),
            grant_type: 'refresh_token',
            org_id: r.org_id,
            refresh_token: r.refresh_token
          }
          // 存储token,存进cookie里面
          store.commit('setTokenInfo', data.token_type + data.access_token);
          // 存储refresh_token
          store.commit('setRefreshToken', rData);
          onRrefreshed(data.token_type + data.access_token);
          /* 执行onRefreshed函数后清空数组中保存的请求 */
          refreshSubscribers = [];
        }).catch(err => {
          console.log(err);
          router.replace({
            path: '/login'
          })
        })
      }
      /* 把请求(token)=>{....}都push到一个数组中 */
      let retry = new Promise((resolve, reject) => {
        /* (token) => {...}这个函数就是回调函数 */
        subscribeTokenRefresh((token) => {
          config.headers.Authorization = token
          /* 将请求挂起 */
          resolve(config)
        })
      })
      return retry
    } else {
      return config
    }
  } else {
    return config
  }
}, (error) => {
  return Promise.reject(error);
})

这样就可以实现,在距离token过期十分钟之后的请求,都会先进行一次token的刷新,并且同时将马上要发起的几个请求放在一个promise的队列当中,等到我的token利用refreshToken刷新到新的token之后,再去取队列当中的http请求,遍历在header头部Authorization添加新的token。再继续发起请求,之后 注意 要清空掉队列中http请求哦~~~~

但是对于用户端来说,(发生了什么,我不清楚???)是没有一点感觉哒,用户体验灰常好~~~


感觉下面大神的分享??

参考链接1?
参考链接2?

Logo

前往低代码交流专区

更多推荐