Token失效的主动介入
流程图转化代码
流程图转化代码 src/utils/auth.js
const timeKey = 'hrsaas-timestamp-key' // 设置一个独一无二的key // 获取时间戳 export function getTimeStamp() { return Cookies.get(timeKey) } // 设置时间戳 export function setTimeStamp() { Cookies.set(timeKey, Date.now()) }
src/utils/request.js
import axios from 'axios' import store from '@/store' import router from '@/router' import { Message } from 'element-ui' import { getTimeStamp } from '@/utils/auth' const TimeOut = 3600 // 定义超时时间 const service = axios.create({ // 当执行 npm run dev => .evn.development => /api => 跨域代理 baseURL: process.env.VUE_APP_BASE_API, // npm run dev => /api npm run build => /prod-api timeout: 5000 // 设置超时时间 }) // 请求拦截器 service.interceptors.request.use(config => { // config 是请求的配置信息 // 注入token if (store.getters.token) { // 只有在有token的情况下 才有必要去检查时间戳是否超时 if (IsCheckTimeOut()) { // 如果它为true表示 过期了 // token没用了 因为超时了 store.dispatch('user/logout') // 登出操作 // 跳转到登录页 router.push('/login') return Promise.reject(new Error('token超时了')) } config.headers['Authorization'] = `Bearer ${store.getters.token}` } return config // 必须要返回的 }, error => { return Promise.reject(error) }) // 响应拦截器 service.interceptors.response.use(response => { // axios默认加了一层data const { success, message, data } = response.data // 要根据success的成功与否决定下面的操作 if (success) { return data } else { // 业务已经错误了 还能进then ? 不能 ! 应该进catch Message.error(message) // 提示错误消息 return Promise.reject(new Error(message)) } }, error => { Message.error(error.message) // 提示错误信息 return Promise.reject(error) // 返回执行错误 让当前的执行链跳出成功 直接进入 catch }) // 是否超时 // 超时逻辑 (当前时间 - 缓存中的时间) 是否大于 时间差 function IsCheckTimeOut() { var currentTime = Date.now() // 当前时间戳 var timeStamp = getTimeStamp() // 缓存时间戳 return (currentTime - timeStamp) / 1000 > TimeOut } export default service
本节注意
:我们在调用登录接口的时候 一定是没有token的,所以token检查不会影响登录接口的调用
同理,在登录的时候,如果登录成功,我们应该设置时间戳
// 定义login action 也需要参数 调用action时 传递过来的参数 // async 标记的函数其实就是一个异步函数 -> 本质是还是 一个promise async login(context, data) { // 经过响应拦截器的处理之后 这里的result实际上就是 token const result = await login(data) // 实际上就是一个promise result就是执行的结果 // axios默认给数据加了一层data // 表示登录接口调用成功 也就是意味着你的用户名和密码是正确的 // 现在有用户token // actions 修改state 必须通过mutations context.commit('setToken', result) // 写入时间戳 setTimeStamp() // 将当前的最新时间写入缓存 }
提交代码
有主动处理就有被动处理,也就是后端告诉我们超时了,我们被迫做出反应,如果后端接口没有做处理,主动介入就是一种简单的方式
本节任务
:完成token超时的主动介入
Token失效的被动处理
目标
: 实现token失效的被动处理
除了token的主动介入之外,我们还可以对token进行被动的处理,如图
token超时的错误码是10002
代码实现 src/utils/request.js
error => { // error 信息 里面 response的对象 if (error.response && error.response.data && error.response.data.code === 10002) { // 当等于10002的时候 表示 后端告诉我token超时了 store.dispatch('user/logout') // 登出action 删除token router.push('/login') } else { Message.error(error.message) // 提示错误信息 } return Promise.reject(error) }
无论是主动介入还是被动处理,这些操作都是为了更好地处理token,减少错误异常的可能性
本节任务
Token失效的被动处理
左侧菜单的显示逻辑,设置菜单图标
目标
解析左侧菜单的显示逻辑, 设置左侧导航菜单的图标内容
上小节中,我们集成了路由,菜单就显示内容了,这是为什么 ?
阅读左侧菜单代码
我们发现如图的逻辑
由于,该项目不需要二级菜单的显示,所以对代码进行一下处理,只保留一级菜单路由
src/layout/components/Sidebar/SidebarItem.vue
<template> <div v-if="!item.hidden"> <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow"> <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)"> <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}"> <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" /> </el-menu-item> </app-link> </template> <!-- <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body> <template slot="title"> <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" /> </template> <sidebar-item v-for="child in item.children" :key="child.path" :is-nest="true" :item="child" :base-path="resolvePath(child.path)" class="nest-menu" /> </el-submenu> --> </div> </template>
本节注意
:通过代码发现,当路由中的属性hidden
为true时,表示该路由不显示在左侧菜单中
与此同时,我们发现左侧菜单并不协调,是因为缺少图标。在本项目中,我们的图标采用了SVG的组件
左侧菜单的图标实际上读取的是meta属性的icon,这个icon需要我们提前放置在src/icons/svg
目录下
该资源已经在菜单svg目录中提供,请将该目录下的所有svg放到
src/icons/svg
目录下
具体的icon名称可参考线上地址
functional为true,表示该组件为一个函数式组件
函数式组件: 没有data状态,没有响应式数据,只会接收props属性, 没有this, 他就是一个函数
模块对应icon
├── dashboard # dashboard ├── departments # tree ├── employees # people ├── setting # setting ├── salarys # money ├── social # table ├── attendances # skill ├── approvals # tree-table ├── permission # lock
按照对应的icon设置图标
本节任务:
理解左侧菜单的生成逻辑,并设置左侧菜单的图标