跳转到主内容
思享编程网:思考分享,玩转编程世界!

关于解决token过期失效问题

关于解决token过期失效问题,用户对token无感知(实现免登陆) 一、先认识下token 二、整体思路 三、实现步骤 1.理清各个文件作用 2.路由导航守卫 3.封装localStorage方法 4.vuex 5.封装axios 实现请求拦截器和响应拦截器(重点部分) 四、小结 一、先认识下token

二、整体思路

三、实现步骤 1.理清各个文件作用

2.路由导航守卫 设置用户有无token访问主页,并且登录成功回到目标页

import Vue from 'vue'

import VueRouter from 'vue-router' import store from '@/store/index.js' Vue.use(VueRouter) const router = new VueRouter({ routes }) // 路由导航守卫 router.beforeEach((to, from, next) => { if (to.path.startsWith('/user')) { // 判断token if (store.state.tokenInfo.token) { next() } else { next({ path: '/login', query: { // 登录成功回到目标页 backto: to.fullPath // fullPath 会拿到路由后面的查询字符串 } }) } } else { next() } }) export default router

3.封装localStorage方法 目的在vuex中调用

/ 封装模块 使用localStorage实现持久化 只是进行保存

// 从localStorage中取出一项数据 名字叫name export const getItem = name => { return JSON.parse(localStorage.getItem(name)) } // 向localStorage中设置一项数据 名字为name里面设置值为obj export const setItem = (name, obj) => { localStorage.setItem(name, JSON.stringify(obj)) } // 删除 export const removeitem = name => { localStorage.removeItem(name) }

4.vuex

import Vue from 'vue'

import Vuex from 'vuex' import { setItem, getItem } from '@/utils/storage.js' Vue.use(Vuex)

export default new Vuex.Store({ state: { // 保存公共数据 tokenInfo: getItem('tokenInfo') || {} }, mutations: { mSetTokenInfo (state, tokenObj) { state.tokenInfo = tokenObj // 因为刷新会丢失所以进行持久化 调用storage方法 setItem('tokenInfo', tokenObj) } }, // -------------------此次重点--------------------------------------------------------- // 只跟新token 不跟新响应拦截器里面的refreshToken mUpdateToken (state, newToken) { state.tokenInfo.token = newToken setItem('tokenInfo', state.tokenInfo) }, actions: { }, modules: { } })

5.封装axios 实现请求拦截器和响应拦截器(重点部分) 关于axios拦截器 可参考官方文档 (点我)axios拦截器官方跳转链接

/* 对axios进行二次封装

请求拦截器增加token 响应拦截器处理大数据 */ import store from '@/store/index.js' import axios from 'axios' import JSONbig from 'json-bigint' // 引入大数字包 import router from '@/router/index.js' /* 以前写法: axios.defaults.baseURL = 'XXX' 自定义写法:const xxx = axios.create({}) 一个项目中可能有不同的基地址 就要用自定义写法设置不同的基地址 */ const instance = axios.create({ baseURL: 'http://ttapi.research.itcast.cn', transformResponse: [function (data) { if (data === '') { return false } try { // 如果没有遇到错误,就返回 JSONbig处理之后的数据 return JSONbig.parse(data) } catch (err) { console.log('JSONbig转换出错', err) return data } }] }) // 在instance上添加请求拦截器 补充请求头token信息 instance.interceptors.request.use(function (config) { // 从vuex中取出token const token = store.state.tokenInfo.token // 如果有token则 添加到headers中 if (token) { config.headers.Authorization = `Bearer ${token}` } return config }, function (error) { return Promise.reject(error) }) //------------------------这里处理token过期-------------------------------------------- // 添加响应拦截器 处理401 token过期 instance.interceptors.response.use(function (response) { return response }, async function (error) { // 如果是401错误 则做以下错误 if (error.response.status === 401) { // 从vuex中取出token const refreshToken = store.state.tokenInfo.token // 是否有refreshToken if (refreshToken) { // 用refresh_token 重发请求 再次取回一个有效期的 try { // 注意这里重新发请求要用axios 不能用封装的instance url地址是根据接口文档写的 const { data: res } = await axios({ method: 'PUT', url: 'http://ttapi.research.itcast.cn/app/v1_0/authorizations', headers: { Authorization: `Bearer ${refreshToken}` } }) // 定义赋值新的token const newToken = res.data.token // 跟新vuex store.commit('mUpdateToken', newToken) // 再发请求 return instance(error.config) } catch { // 如果没有拿到新的token // 回登录页 router.push({ path: '/login', query: { // currentRoute表示当前路由对象 backto: router.currentRoute.fullPath } }) } } else { // 如果没有refreshToken router.push({ path: '/login', query: { backto: router.currentRoute.fullPath } }) } } else { // 如果不是401错误 return Promise.reject(error) } }) export default instance

四、小结

相关文章