Token Refresh Introduction
- Single token, used for login judgment
- Toekn expired automatic refresh
- Reject all front-end judgment tokens
- Database storage token last refresh time and refresh times
- Up to 20 refreshes
- If you have not logged in for 3 days, you need to log in again to refresh the token
token refresh rules
- The token expires and is automatically refreshed, and the number of refreshes is accumulated, the upper limit is 20 refreshes, and the token cannot be refreshed more than 20 times, and you need to log in again
- If the last refresh time was 3 days ago, that is, if you have not logged in for 3 days, you cannot refresh the token and you need to log in again
front-end code
Package of Axios
- The role of packaging
- When initiating a token update request, if there are other requests, use promise to suspend the request first and push it to an array
- After the token request returns the result, re-initiate the request and execute the push array
- The backend status code is
456
indicating that the token has expired
scr/api/axios.js
import axios from 'axios'
import {
storeToRefs } from 'pinia'
import useUserInfoStore from '@/stores/userInfo'
// 创建一个 axios 实例
const service = axios.create({
timeout: 5000,
})
let tokenUpdateing = false,//token是否处于更新中
reqLists = []//更新token时请求的队列
// 请求拦截器
service.interceptors.request.use(config => {
// 带上token发起请求
const userInfoStore = useUserInfoStore(),
{
auth } = storeToRefs(userInfoStore)
auth && (config.headers.auth = auth.value)
return config
}, error => {
// return error
Promise.reject(error)
})
// 响应拦截器
service.interceptors.response.use(async res => {
const {
statu } = res.data,
{
url, method, params } = res.config
// token过期
if (statu === 456) {
const reqConfig = {
url, method, params }
// 更新token中,先将请求配置push到reqLists,token更新完成后再重新发起请求
if (tokenUpdateing === true) {
//token更新中,将请求挂起
return new Promise(resolve => {
// token更新中,push请求 ,不push相同的请求
const findRepeat = reqLists.findIndex(val => JSON.stringify(val) === JSON.stringify(reqConfig))
if (findRepeat === -1) reqLists.push(reqConfig)
resolve(service(reqConfig))
})
// 开始更新token
} else {
tokenUpdateing = true
const uid = 6666,//用户id
{
statu, msg } = await service({
//向后端请求新token
url: `/api/updatetoken`,
params: {
uid,
sign: MD5(uid + 'usersid')//md5签名,防止篡改请求
}
}),
userInfoStore = useUserInfoStore()//重点:pinia仓库,作用:存储token
// token请求成功
if (statu === 200) {
// 请求成功,更新token到pinia
userInfoStore.$patch(state => {
state.auth = msg
})
} else {
// token更新失败,重置pinia仓库
userInfoStore.$reset()
}
//token更新完成 ——> 重新发起请求
reqLists.forEach(it => service(it))
reqLists = []//清空请求队列
tokenUpdateing = false //关闭token更新
// 重新发起请求
return service(reqConfig)
}
}
return res.data
}, error => {
Promise.reject(error)
})
export default service
store (pinia persistent storage)
- pinia official website - https://pinia.web3doc.top/core-concepts/state.html#%E8%AE%BF%E9%97%AE-%E2%80%9Cstate%E2%80%9D
- pinia-plugin-persistedstate (pinia persistent repository) - https://prazdevs.github.io/pinia-plugin-persistedstate/zh/guide/config.html
scr/store/store.js
import {
defineStore } from 'pinia'
const useUserInfoStore = defineStore('userInfo', {
state: () => {
return {
userName: null,
logined: false,//是否登录
uid: null,
jianjie: null,
auth: null,//登录的token
showLoginForm: false,//显示登录/注册表单
}
},
persist: {
key: 'userInfo',
paths: ['auth'],
}
})
export default useUserInfoStore