使用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) } 

相关内容

热门资讯

透视线上“智星德州菠萝插件官网... 透视线上“智星德州菠萝插件官网”其实是有挂(辅助挂)详细辅助德州论坛1、首先打开最新版本,在首页我们...
透视规律!wpk辅助器,佛手在... 透视规律!wpk辅助器,佛手在线十三道辅助器(切实是真的有挂)1、每一步都需要思考,不同水平的挑战会...
aapoker辅助功能!wep... aapoker辅助功能!wepoker买脚本靠谱吗,德普之星怎么作弊(详细辅助教你攻略)是一款可以让...
透视线上!德普之星辅助器,we... 1、透视线上!德普之星辅助器,we-poker辅助(详细辅助安装教程)。2、德普之星辅助器透视辅助简...
透视神器“德普之星怎么作弊”竟... 透视神器“德普之星怎么作弊”竟然真的是有挂(辅助挂)详细辅助扑克教程1、这是跨平台的黑科技,在线的操...
透视ai代打!wepoker一... 透视ai代打!wepoker一直输的号能继续打吗,蘑菇云辅助使用视频(都是存在有挂)1、完成蘑菇云辅...
智星菠萝辅助怎么买!hhpok... 智星菠萝辅助怎么买!hhpoker哪个俱乐部靠谱,德普之星辅助正版(详细辅助插件教程);致您一封信;...
透视能赢!德普之星辅助器app... 透视能赢!德普之星辅助器app,aapoker公共底牌(详细辅助透视教程);亲真的是有正版授权,小编...
透视规律“红龙poker透视”... 透视规律“红龙poker透视”好像存在有挂(辅助挂)详细辅助德州论坛1、用户打开应用后不用登录就可以...
透视安卓版!wepoker私人... 透视安卓版!wepoker私人局怎么玩,微乐家乡自建房辅助app(确实是真的有挂)1、操作简单,无需...