【Token+Vue3】token无感刷新 | token自动刷新 | token过期

token刷新介绍

  1. 单token,用于登录判断
  2. toekn过期自动刷新
  3. 拒绝一切前端判断token
  4. 数据库存储token最后刷新时间与刷新次数
    • 刷新次数上限20
    • 未登录3天需重新登录来刷新token

token刷新规则

  1. token过期自动刷新,并累加刷新次数,上限刷新20次,超过20次无法刷新token,需重新登录
  2. 若最后刷新时间是3天前,也就是3天没有登录过,无法刷新token,需重新登录

前端代码

Axios的封装

  • 封装的作用
    1. 发起token更新请求时,若有其它请求,利用promise将请求先挂起,并push到一个数组
    2. token请求返回结果后,再重新发起请求,执行push的数组
    3. 后端状态码为456示token过期

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持久化存储)

  • pinia官网 - https://pinia.web3doc.top/core-concepts/state.html#%E8%AE%BF%E9%97%AE-%E2%80%9Cstate%E2%80%9D
  • pinia-plugin-persistedstate (pinia持久化存储库)- 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

猜你喜欢

转载自blog.csdn.net/qq_43614372/article/details/131387406