在系统登录后,后端返回一个token,和refreshToken。每次接口请求的时候都会携带这个token,但是这个token一般是有过期时间的,假设过期时间为半小时,你半小时内没有调接口。半小时后你再调接口,会报401错误,代表token过期,这个时候前端有两种解决方案,第一种也就是退出登录,让用户重新登录,这种比较简单。但是我们的经理不希望用户再次登录,而是希望这个token能自动更新,我就稍微的研究了一下,发现可行,所以记录到此,方便日后查看

自动刷新token的原理就是:

在axios响应拦截器中判断http状态是否是401,如果是,则拿着refreshToken去调接口,接口会返回新的token和refreshToken,将新token和refreshToken在vuex中从新赋值。然后继续调刚才报401的那个接口,这时候携带新token去请求就可以了

request.js

import axios from 'axios'
import store from '@/store'
import storage from 'store'
import notification from 'ant-design-vue/es/notification'
import { message } from 'ant-design-vue'
import { VueAxios } from './axios'
import { ACCESS_TOKEN } from '@/store/mutation-types'

// 创建 axios 实例
const request = axios.create({
  // API 请求的默认前缀
  baseURL: process.env.VUE_APP_API_BASE_URL,
  timeout: 6000 // 请求超时时间
})

const mytoken = `Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJJRCI6IjI5MTYzOTA1NzgyNzc1MTkzNjAiLCJOQU1FIjoiZHVhbnJvbmd5YW8iLCJuYmYiOjE2NDE5NzkwNzcsImV4cCI6MTY0MTk4MDg3NywiaXNzIjoiaHR0cDovLzM5LjEwMy4yMTUuNTE6MzAwMDQiLCJhdWQiOiJLYXlUdW5lIn0.b6Ps4BqI4BH6qDYbxTVGo72ctoUxL-9G_woXx_askrA`


// 异常拦截处理器
const errorHandler = (error) => {
  // console.log(error.response);

  if(error.message == 'Network Error') {
      message.error('系统异常')
  }
  if (error.response) {
    const data = error.response.data
    // 从 localstorage 获取 token
    const token = storage.get(ACCESS_TOKEN)
    if (error.response.status === 403) {
      notification.error({
        message: 'Forbidden',
        description: data.message
      })
    }
    // 判断http状态是否是401
    if (error.response.status === 401) {
      // 调接口,刷新token
      store.dispatch('RefreshToken').then(() => {
        // 再发请求
        return request(error.config)
      }).catch((err)=>{
        message.error('系统异常')
      })
    }
  }
  return Promise.reject(error)
}

// request interceptor
request.interceptors.request.use(config => {
  const accessToken = store.getters.token
  const token = storage.get(ACCESS_TOKEN)
  // 如果 token 存在
  // 让每个请求携带自定义 token 请根据实际情况自行修改
  if (token) {
    config.headers['Access-Token'] = token
  }
  config.headers['Authorization'] = `Bearer ${accessToken}`
  return config
}, errorHandler)

// response interceptor
request.interceptors.response.use((response) => {
  if(response.data instanceof Blob) {
    return response
  }
  return response.data
}, errorHandler)

const installer = {
  vm: {},
  install (Vue) {
    Vue.use(VueAxios, request)
  }
}

export default request

export {
  installer as VueAxios,
  request as axios
}

user.js

import storage from 'store'
// import { login, getInfo, logout } from '@/api/login'
import { getInfo, logout, refreshTokenFn } from '@/api/login'
import { ACCESS_TOKEN, REFRESH_TOKIN } from '@/store/mutation-types'
import { welcome } from '@/utils/util'

const user = {
  state: {
    token: '',
    refreshToken: '',
    name: '',
    welcome: '',
    avatar: '',
    roles: [],
    info: {},
    systemId: ''
  },

  mutations: {
    SET_TOKEN: (state, token) => {
      state.token = token
    },
    SET_RETOKEN: (state, refreshToken) => {
      state.refreshToken = refreshToken
    },
    SET_NAME: (state, { name, welcome }) => {
      state.name = name
      state.welcome = welcome
    },
    SET_AVATAR: (state, avatar) => {
      state.avatar = avatar
    },
    SET_ROLES: (state, roles) => {
      state.roles = roles
    },
    SET_INFO: (state, info) => {
      state.info = info
    },
    SET_SYSTEMID: (state, data) => {
      state.systemId = data
    }
  },

  actions: {
    // 登录
    Login ({ commit }, userInfo) {
      return new Promise((resolve, reject) => {
        if (!userInfo.accessToken) {
            reject(new Error('403'))
        }
        storage.set(ACCESS_TOKEN, userInfo.accessToken, 7 * 24 * 60 * 60 * 1000)
        storage.set(REFRESH_TOKIN, userInfo.refreshToken, 7 * 24 * 60 * 60 * 1000)
        commit('SET_TOKEN', userInfo.accessToken)
        commit('SET_RETOKEN', userInfo.refreshToken)

        resolve()
        // login(userInfo).then(response => {
        //   const result = response.result
        //   storage.set(ACCESS_TOKEN, result.token, 7 * 24 * 60 * 60 * 1000)
        //   commit('SET_TOKEN', result.token)
        //   resolve()
        // }).catch(error => {
        //   reject(error)
        // })
      })
    },

    // 获取用户信息
    GetInfo ({ commit }) {
      return new Promise((resolve, reject) => {
        getInfo().then(response => {
          const result = response.result
          console.log('result', result)

          if (result.role && result.role.permissions.length > 0) {
            const role = result.role
            role.permissions = result.role.permissions
            role.permissions.map(per => {
              if (per.actionEntitySet != null && per.actionEntitySet.length > 0) {
                const action = per.actionEntitySet.map(action => { return action.action })
                per.actionList = action
              }
            })
            role.permissionList = role.permissions.map(permission => { return permission.permissionId })
            commit('SET_ROLES', result.role)
            commit('SET_INFO', result)
          } else {
            reject(new Error('getInfo: roles must be a non-null array !'))
          }

          commit('SET_NAME', { name: result.name, welcome: welcome() })
          commit('SET_AVATAR', result.avatar)

          resolve(response)
        }).catch(error => {
          reject(error)
        })
      })
    },

    // 登出
    Logout ({ commit, state }) {
      return new Promise((resolve) => {
        logout(state.token).then(() => {
          commit('SET_TOKEN', '')
          commit('SET_ROLES', [])
          storage.remove(ACCESS_TOKEN)
          resolve()
        }).catch((err) => {
          console.log('logout fail:', err)
          // resolve()
        }).finally(() => {
        })
      })
    },

    // 刷新token
    RefreshToken({commit, state}) {
      return new Promise((resolve, reject)=>{
        const refreshToken = `${state.refreshToken}`
        refreshTokenFn({refreshToken}).then((res)=>{
          if(res.code == 1) {
            commit('SET_TOKEN', res.data.accessToken)
            commit('SET_RETOKEN', res.data.refreshToken)
            resolve()
          }else {
            reject()
          }
          
        }).catch((err) => {
          reject(err)
        }).finally(() => {

        })
      })
    }

  }
}

export default user

refreshTokenFn函数

/**
 * 刷新token
 * @param {*} parameter 
 * @returns 
 */
export function refreshTokenFn (parameter) {
  return request({
    // url: `${userApi.RefreshToken}?refreshToken=${parameter.refreshToken}`,
    url: `${userApi.RefreshToken}`,
    method: 'post',
    headers: { 'content-type': 'application/x-www-form-urlencoded' },
    data: qs.stringify(parameter),
  })
}

 

Logo

前往低代码交流专区

更多推荐