核心实现方式: 使用 js-cookie 插件将 token 存储到 cookie 中
(-- @/store/modules/user.js;state 配置项)
token: getToken()
(-- 同上;mutations 配置项)
setToken(state, token) {state.token = tokensetToken(token)
}
(-- 同上;actions 配置项)
async login(context, data) {const result = await login(data)context.commit('setToken', result)
}
(-- @/views/login/index.vue)
import { mapActions } from 'vuex'
methods() {...mapActions(['user/login'])
}
async login() { // 登录-- 增await this.$store.dispatch('user/login', this.loginForm)--this.$router.push({name: 'Dashboard'})
}
核心实现方式: 在请求拦截器中的请求头中携带 token
(-- @/utils/request.js)
service.interceptors.request.use(config => { // 请求拦截器-- 增if (store.getters.token) { // 在请求头中携带 tokenconfig.headers['Authorization'] = `${store.getters.token}`}--return config
})
核心实现方式: 获取 token 时,将当前时间戳一起存储到缓存中。每当发起请求时,判断(当前时间戳 - 缓存中的时间戳)/ 1000 如果大于过期时间,表示 token 过期,清空 token,跳转到登录页,抛出时间戳过期提示
(-- @/utils/auth.js)
const timeKey = 'hrsaas-timestamp-key' // 时间戳
export function getTimeStamp() { // 获取 时间戳return Cookies.get(timeKey)
}
export function setTimeStamp() { // 设置 时间戳Cookies.set(timeKey, Date.now())
}
(-- @/views/login/index.vue)
-- 增
import { setTimeStamp } from '@/utils/auth'
--
async login(content, data) { // 登录...context.commit('setToken', result)-- 增setTimeStamp()--
}
(-- @/utils/request.js)
-- 增
import { getTimeStamp } from '@/utils/auto'
import router from '@/router'
const TimeOut = 3600 // token 过期时间。3600 毫秒 = 一小时
function IsCheckTimeOut() { // 判断 token 是否过期var currentTime = Date.now() // 当前时间戳var timeStamp = getTimeStamp() // 缓存时间戳return (currentTime - timeStamp) / 1000 > TimeOut // 判断 token 是否过期 // 公式:【(当前时间戳 - 缓存中的时间戳)/ 1000 如果大于过期时间,表示 token 过期】。这里的除 1000 是将毫秒转化成秒。
}
--
// 请求拦截器
if (store.getters.token) {-- 增if (IsCheckTimeOut()) { // 判断 token 是否过期store.dispatch('user/logout') // 调用登出方法router.push('/login')return Promise.reject(new Error('token 超时了'))}--
}
核心实现方式: 在响应拦截器中判断后端响应的状态码,如果是 401 则表示 token 过期,然后清空 token、和 vuex 中的 token 即可
(-- @/utils/request.js)
-- 增
import store from '@/store'
import router from '@/router'
--
// 响应拦截器
service.interceptors.response.use(response => {...
}, error => {-- 增if (error.response && error.response.data && error.response.data.code === 10002) { // 判断 token 是否过期// 调用登出方法store.dispatch('user/logout')router.push('/login')} else {-- 改(新)Message.error(error.message) // 提示错误信息--}return Promise.reject(error)---- 改(旧)Message.error(error.message) // 提示错误信息
})
核心实现方式: 1、清空 state 中的 token 2、清空 cookie 中的 token 3、清空 用户信息
核心实现方式: 导航守卫。在前置守卫中(判断是否有 token(如果有 token 在通过前置守卫的第一个参数判断是否访问的是 登录页,如果是登录页则调用前置守卫的第三个参数跳转到首页))
(-- @/新建 permission.js)
import router from '@/router'
import nprogress from 'nprogress'
import 'nprogress/nprogress.css' // 引入进度条样式
import store from '@/store'
const whiteList = ['/login', '/404', '/demo'] // 白名单
router.beforeEach((to, from, next) => { // 前置守卫 // (参数一:将要 访问 路由的信息对象)(参数二:将要 离开 路由的信息对象)(参数三:是一个函数,表示放行,允许这次路由导航)nprogress.start() // 开启进度条if (store.getters.token) { // 判断 是否有 tokenif (to.path === '/login') { // 判断 是否前往 登录页next('/')} else {next()}} else {if (whiteList.includes(to.path)) { // 判断 前往的地址是否在白名单中next()} else {next('/login')}}nprogress.done() // 解决手动切换地址时,进度条不关闭的问题
})
router.afterEach(() => { // 后置守卫nprogress.done() // 关闭进度条
})