使用axios实现vue web前端无痕刷新
创始人
2025-01-07 22:32:36
0

本文使用刷新接口去实现Token的无痕刷新,当拦截器检测到接口返回401响应码(即:认证失败),在拦截器中调用刷新接口去刷新Token,如果返回402(即:刷新token失效)则跳转到登录页,否则就更新Token信息。

定义相关接口

import request from '@/utils/request'  export function login(data) {   return request({     url: '/api/user/login',     method: 'post',     data   }) }  export function getInfo() {   return request({     url: '/api/user/info',     method: 'get'   }) }  export function tokenRefresh(data) {   return request({     url: '/api/user/token/refresh',     method: 'post',     data   }) }  export function logout() {   return request({     url: '/api/user/logout',     method: 'post'   }) } 

Token信息

{     "code": 200,     "msg": "成功",     "data": {         "accessToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEsInJvbGVJZHMiOiIxIiwibmFtZSI6ImFkbWluIiwiZGVwdElkIjoxLCJ0eXBlIjowLCJqdGkiOiI5Y2Y3MzAwMC00YjNiLTRjYzAtYTI1YS01ZDM5YjFhYmFlMDgiLCJleHAiOjE3MjA2ODkyNTAsImlhdCI6MTcyMDY4OTE5MCwic3ViIjoiUGVyaXBoZXJhbHMiLCJpc3MiOiJPY2VhbiJ9.0-E4S5NuXNZCNslhyVpBjFZVCIqDahn6wdBt0gAxxmU",         "accessTokenExpireIn": 1720689250,         "refreshToken": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1aWQiOjEsInJvbGVJZHMiOiIxIiwibmFtZSI6ImFkbWluIiwiZGVwdElkIjoxLCJ0eXBlIjoxLCJqdGkiOiIwZDEzMWUzNC1lOGNiLTRhZjItOTMyZC1iN2JlNzQzZDgzZjgiLCJleHAiOjE3MjA2OTYzOTAsImlhdCI6MTcyMDY4OTE5MCwic3ViIjoiUGVyaXBoZXJhbHMiLCJpc3MiOiJPY2VhbiJ9.TBfL8cNciiS9GbX-2T1ejWWHYdyrUzkJELixAcm8EJ0",         "refreshTokenExpireIn": 1720696390     } } 

定义前端拦截器 request.js

import axios from 'axios' import { Message } from 'element-ui' import { getToken, getRefreshToken, setToken, removeToken } from '@/utils/auth' import { tokenRefresh } from '@/api/user'  // 创建 axios 实例 const service = axios.create({   // 请求地址前缀   baseURL: process.env.VUE_APP_BASE_API,   // 请求5s超时   timeout: 5000 // request timeout })  // Request 拦截器 service.interceptors.request.use(      config => {      // 从cookie中获取令牌信息,并放入接口头信息中     const token = getToken()     if (token) {       config.headers['Authorization'] = token     }      return config   },   error => {     // do something with request error     console.log(error) // for debug     return Promise.reject(error)   }  )  // 刷新令牌的标记 let isRefreshing = false  // 重试请求队列 let requests = []  // Response 拦截器 service.interceptors.response.use(      response => {          const res = response.data     if (res.code === 200) {       return res     }      if(res.code === 402) {       removeToken()       location.reload()     }      // 401: 认证失败,402:令牌过期     if(res.code === 401) {        const refreshToken = getRefreshToken()       if(!isRefreshing) {                  isRefreshing = true         // 刷新令牌,刷新成功后进行客户端令牌更新         return tokenRefresh( {refreshToken: refreshToken} ).then(result => {                      const data = result.data           setToken(data.accessToken, data.refreshToken)            const token = data.accessToken           response.config.headers['Authorization'] = token           // token 刷新后将数组的方法重新执行           requests.forEach((request) => request(token))           // 重新请求完清空           requests = []             return service(response.config)         }).catch(() => {           removeToken()           location.reload()         }).finally(() => {           isRefreshing = false         })        } else {         // 返回未执行 resolve 的 Promise         return new Promise(resolve => {           // 用函数形式将 resolve 存入,等待刷新后再执行           requests.push(token => {             response.config.headers['Authorization']  = token             resolve(service(response.config))           })         })       }     }      Message({       message: res.msg || 'Error',       type: 'error',       duration: 5 * 1000     })      return Promise.reject(new Error(res.msg || 'Error'))   },   error => {     console.log('err' + error) // for debug     Message({       message: error.msg,       type: 'error',       duration: 5 * 1000     })          return Promise.reject(error)   } )  export default service 

定义Token校验路由跳转 permission.js

import router from './router' import store from './store' import { Message } from 'element-ui' import NProgress from 'nprogress' // progress bar import 'nprogress/nprogress.css' // progress bar style import { getToken } from '@/utils/auth' // get token from cookie import getPageTitle from '@/utils/get-page-title'  NProgress.configure({ showSpinner: false }) // NProgress Configuration  const whiteList = ['/login'] // no redirect whitelist  router.beforeEach(async(to, from, next) => {   // start progress bar   NProgress.start()    // set page title   document.title = getPageTitle(to.meta.title)    // determine whether the user has logged in   const hasToken = getToken()    if (hasToken) {     if (to.path === '/login') {       // if is logged in, redirect to the home page       next({ path: '/' })       NProgress.done()     } else {       const hasGetUserInfo = store.getters.name       if (hasGetUserInfo) {         next()       } else {         try {           // get user info           await store.dispatch('user/getInfo')            next()         } catch (error) {           // remove token and go to login page to re-login           await store.dispatch('user/resetToken')           Message.error(error || 'Has Error')           next(`/login?redirect=${to.path}`)           NProgress.done()         }       }     }   } else {     /* has no token*/      if (whiteList.indexOf(to.path) !== -1) {       // in the free login whitelist, go directly       next()     } else {       // other pages that do not have permission to access are redirected to the login page.       next(`/login?redirect=${to.path}`)       NProgress.done()     }   } })  router.afterEach(() => {   // finish progress bar   NProgress.done() }) 

Token前端缓存 auth.js

const TokenKey = 'accessToken' const RefreshTokenKey = 'refreshToken'  export function getToken() {   return localStorage.getItem(TokenKey) }  export function getRefreshToken() {   return localStorage.getItem(RefreshTokenKey) }  export function setToken(accessToken, refreshToken) {   localStorage.setItem(TokenKey, accessToken)   localStorage.setItem(RefreshTokenKey, refreshToken) }  export function removeToken() {   localStorage.removeItem(TokenKey)   localStorage.removeItem(RefreshTokenKey) } 

相关内容

热门资讯

避坑细节Wepoke代打ai软... 避坑细节Wepoke代打ai软件透明挂!太夸张了其实真的是有挂(有挂分析)(哔哩哔哩)是一款可以让一...
指导大家《Wepoke》软件透... 指导大家《Wepoke》软件透明挂!(透明挂)软件工具(2025已更新)(哔哩哔哩)指导大家《Wep...
第三方教程《微扑克辅助测试》微... 第三方教程《微扑克辅助测试》微扑克wpk外挂辅助插件(哔哩哔哩);最新版2024是一款经典耐玩的益智...
科普攻略微扑克网页版原来确实是... 您好,微扑克这款游戏可以开挂的,确实是有挂的,需要了解加微【841106723】很多玩家在这款游戏中...
AI教程!微扑克wpk(WPk... AI教程!微扑克wpk(WPk)透视辅助!(辅助透视)详细教程(2020已更新)(哔哩哔哩);AI智...
2024版教程微扑克原来是有挂... 2024版教程微扑克原来是有挂,太坑了原来真的是有挂,详细教程(有挂分析)是一款可以让一直输的玩家,...
实测发现!微扑克辅助工具(辅助... 实测发现!微扑克辅助工具(辅助挂)原来确实是有挂(有挂神器)详细教程(哔哩哔哩);超受欢迎的微扑克小...
实操分享wepoker软件透明... 您好,wepoke这款游戏可以开挂的,确实是有挂的,需要了解加微【136704302】很多玩家在这款...
今日重大通报!微扑克软件外挂辅... 今日重大通报!微扑克软件外挂辅助插件(辅助挂)原来是有挂(确实有挂)详细教程(哔哩哔哩)今日重大通报...
热点推荐微扑克系统原来是真的有... 热点推荐微扑克系统原来是真的有挂,太坏了原来真的是有挂,详细教程(有挂解密)是一款可以让一直输的玩家...