vue项目实现token无感刷新

背景

最近在使用系统的过程中,业务人员反馈刚登录一会就提示token过期需要重新登录,这样体验很不友好,他们想要把过期时间设置长一点,不想频繁去登陆。

思考

如果token时间设置的太长,会有安全的问题;如果可以检测到token过期,然后请求新的token替换过期的token,再去请求接口,这样token过期,做到用户无感知。

实现

检测token过期可以主动和被动的去处理,简单来说,主动判断就是在token过期前就处理,被动的就是token过期后再去处理。
以下从用三个方法来实现token的无感刷新。

1.通过返回过期字段判断

通过token认证接口返回的过期字段判断,然后本地时间进行对比,如果过期就重新获取token,这个也有缺点,如果本地时间不准确,会存在判断失误问题。

2.通过定时刷新获取token

写个全局定时器,定时刷新token。这个方法显然不好,不建议使用。

3.通过axios响应拦截器中拦截,判断token 返回过期后,调用刷新token接口

实现:

// 创建 axios 实例
const request = axios.create({
  // API 请求的默认前缀
  baseURL: baseUrl,
  withCredentials: true,
  timeout: 30000 // 请求超时时间
})
// 此处是为了为了防止多次刷新token,可以通过一个变量isRefreshing 去控制是否在刷新token的状态。
let isRefreshing = false // 是否正在刷新的标记
此次为了解决同时发起两个或两个以上的请求时,过期如何处理
let requests = [] // 重试队列
// 异常拦截处理器
const errorHandler = error => {
  if (error.response) {
   //token过期状态码
    if (error.response.status === 401) {
      if (!isRefreshing) {
        // 正在刷新,执行else里面的逻辑
        isRefreshing = true
        return store.dispatch('RefreshToken',store.state.user.refresh_token).then(res => {
//获取新的token,这里的逻辑自行处理,access_token和refresh_token都需要替换保存
          error.config.headers.Authorization = 'Bearer ' + res.access_token
           // token 请求成功后将数组的方法重新执行
          requests.forEach((cb) => cb(res.access_token))
          requests = [] // 重新请求完清空
          return request(error.config)
        }).catch(() => {
          // 如果刷新的refresh_token也过期了,重新登录
          notification.error({
            message: 'token过期',
            description: '请重新登录'
          })
          if (token) {
            store.dispatch('Logout').then(() => {
              window.location.reload()
            })
          }
        }).finally(() => {
          isRefreshing = false
        })
      } else {
        // 返回未执行 resolve 的 Promise
        return new Promise(resolve => {
          // 用函数形式将 resolve 存入,等待刷新后再执行
          requests.push(token => {
            error.config.headers.Authorization = 'Bearer ' + token
            resolve(request(error.config))
          })
        })
      }
    }
  }
  return Promise.reject(error)
}

request.interceptors.response.use(response => {
 //......
}, errorHandler)

你可能感兴趣的:(javascriptaxios)