vue 无感刷新token

何为双 token

– accessToken : 用户获取数据权限

– refreshToken : 用来获取新的accessToken

双 token 验证机制,其中 accessToken 过期时间较短,refreshToken 过期时间较长。当 accessToken 过期后,使用 refreshToken 去请求新的 token。

无感刷新:

当客户端检测到access token即将过期或已经过期时,自动在后台向认证服务器发起请求,携带refresh token换取新的access token。这个过程对用户来说是无感知的,即用户不需要重新登录,页面也不会中断或刷新,因此被称为“无感刷新”。

实现方式:

当 accessToken 过期时,调接口,会返回201,表示token过期,这个时候需要调用 refreshToken 接口,重新获取新的token,在这个期间执行的请求,都存放到一个新的请求队列中,当获取新的token之后再重新调用,接口返回202的时候表示 refreshToken 过期,需要给用户提示,重新登录页面,跳转到登录页

具体步骤:

1.先再store 中定义接口,存储 refreshToken 和 accessToken ,定义刷新token接口,修改 refreshToken 和 accessToken
import { login,refreshToken} from '@/api/login'

const user = {
  state: {
    access_token: getStore({
      name: 'access_token'
    }) || '',
    refresh_token: getStore({
      name: 'refresh_token'
    }) || '',
  },

  mutations: {
    SET_ACCESS_TOKEN(state, token) {
      state.access_token = token
      setStore({
        name: 'access_token',
        content: state.access_token,
        type: 'session'
      })
    },
    SET_REFRESH_TOKEN: (state, rfToken) => {
      state.refresh_token = rfToken
      setStore({
        name: 'refresh_token',
        content: state.refresh_token,
        type: 'session'
      })
    },
  },

  actions: {
    // 登录
    Login({ commit }, userInfo) {
      const loginname = userInfo.loginname.trim()
      const password = userInfo.password
      return new Promise((resolve, reject) => {
        login(loginname, password).then(res => {
          clearStore()
          clearStore({ type: 1 })
          commit('SET_ACCESS_TOKEN', res.data.accessToken)
          commit('SET_REFRESH_TOKEN', res.data.refreshToken)
          resolve()
        }).catch(error => {
          reject(error)
        })
      })
    },
    // 刷新token
    RefreshToken({ commit, state }) {
      return new Promise((resolve, reject) => {
        refreshToken({refreshToken:state.refresh_token}).then(res => {
          if(res.success){
            commit('SET_ACCESS_TOKEN', res.data.accessToken)
            commit('SET_REFRESH_TOKEN', res.data.refreshToken)
          } 
          resolve(res)
        }).catch(error => {
          reject(error)
        })
      })
    },
  }
}


export default user
2.再在请求拦截器中针对不同返回值来处理token情况
//1引入
import axios from 'axios'
import NProgress from 'nprogress' // progress bar
import { Message, MessageBox, Notification } from 'element-ui'
import store from '@/store'
import errorCode from '@/util/errorCode'
import 'nprogress/nprogress.css'
import { baseURL, buildEnv, env } from './baseURL'
axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
//2创建axios实例
let service = axios.create({
baseURL: baseURL[buildEnv],
timeout: 6000
})
// 返回其他状态吗
service.defaults.validateStatus = function (status) {
return status >= 200 && status <= 500 // 默认的
}
// 跨域请求,允许保存cookie
service.defaults.withCredentials = true
// NProgress Configuration
NProgress.configure({
showSpinner: false
})
//创建拦截器
service.interceptors.request.use(
config => {
NProgress.start()
// 是否需要设置 token
const isToken = (config.headers || {}).isToken === false
const token = store.getters.access_token
if (token && !isToken) {
config.headers['Authorization'] = token// 让每个请求携带自定义token 
}
return config
},
error => {
console.log(error);
return Promise.reject(error);
}
)
//标志当前是否正在刷新token
var isRefreshing = true
//请求队列
var requests = []
service.interceptors.response.use(
response => {
NProgress.done()
let res = response.data;
const config = response.config;
if (!res.success) {
// 未设置状态码则默认成功状态
const code = Number(res.errorCode)
// 获取错误信息
const msg = res.errorMsg || errorCode[code] || errorCode.default['default']
// 令牌无效 
if (code === 200 || code === 202) {
logout()
} else if (code === 201) {
//访问令牌过期
if (isRefreshing) {
isRefreshing = false
store.dispatch('RefreshToken')
.then(res => {
if (res.success) {
// 执行失效函数
requests.forEach((cb) => cb())
//重新请求完清空
requests = []
return service(config)
}
})
.finally(() => {
isRefreshing = true;
});
}
// 返回未执行 resolve 的 Promise
return new Promise(resolve => {
// 用函数形式将 resolve 存入,等待刷新后再执行
requests.push(() => {
resolve(service(config));
});
});
}
else {
Message({
message: msg,
type: 'error'
})
return Promise.resolve(res)
}
} 
return Promise.resolve(res)
},
error => {
NProgress.done()
let { message } = error;
Message({
message: message,
type: 'error',
duration: 5 * 1000
})
return Promise.reject(error)
}
)
// 退出
const logout = () => {
MessageBox({
message: '登录状态已过期,请重新登录',
type: 'error',
lockClickModal: false // 设置为false,点击弹窗外围不关闭弹窗
}).then(() => {
store.dispatch('LogOut').then(() => {
store.commit('cleanMenu')
// 刷新登录页面,避免多次弹框
window.location.reload()
})
})
}
export default service
3.具体截图 页面 请求

vue 无感刷新token

原文链接:https://juejin.cn/post/7348362217145106470 作者:用户5327161192068

(0)
上一篇 2024年3月21日 下午4:57
下一篇 2024年3月21日 下午5:08

相关推荐

发表回复

登录后才能评论