携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第12天,点击查看活动详情
搭建登录架构解决方案与实现
这一篇,我们来看一看本地缓存及登录鉴权的相关内容
本地缓存处理方案
通常状态下,我们获取到 token 后,会将其进行缓存,而缓存的方案实际上有两种:
1、本地缓存:LocalStorage
2、全局状态管理:Vuex
保存在 LocalStorage 中是为了实现自动登录
而保存在 vuex 中则是为了其他地方的使用
下边来看一看两种缓存方案的实现:
LocalStorage
1、创建 utils/storage.js 文件,封装三个对应的方法
/**
* 存储数据
*/
export const setItem = (key, value) => {
// 将数组、对象类型的数据转化为 JSON 字符串进行存储
if (typeof value === 'object') {
value = JSON.stringify(value)
}
window.localStorage.setItem(key, value)
}
/**
* 获取数据
*/
export const getItem = key => {
const data = window.localStorage.getItem(key)
try {
return JSON.parse(data)
} catch (err) {
return data
}
}
/**
* 删除数据
*/
export const removeItem = key => {
window.localStorage.removeItem(key)
}
/**
* 删除所有数据
*/
export const removeAllItem = key => {
window.localStorage.clear()
}
Vuex
为了方便获取 token 的常量名,我们需要创建 constant 目录,创建 constant/index.js,这个文件将来也可用来保存其他的常量
export const TOKEN = 'token'
在 vuex 的 user 模块下对 token 进行处理
import { login } from '@/api/sys'
import md5 from 'md5'
import { setItem, getItem } from '@/utils/storage'
import { TOKEN } from '@/constant'
export default {
namespaced: true,
state: () => ({
token: getItem(TOKEN) || ''
}),
mutations: {
setToken(state, token) {
state.token = token
setItem(TOKEN, token)
}
},
actions: {
login(context, userInfo) {
const { username, password } = userInfo
return new Promise((resolve, reject) => {
login({
username,
password: md5(password)
})
.then(data => {
this.commit('user/setToken', data.data.data.token)
resolve()
})
.catch(err => {
reject(err)
})
})
}
}
}
至此,我们登录的时候就可以将 token 存储在 vuex 以及 localStorage
响应数据统一处理
上边我们保存 token 时是通过 data.data.data.token 进行获取的,但这这种写法着实让人感觉难受,所以我们通过 axios 的响应拦截器对其进行一下处理
在 utils/request.js 中增加如下内容
import axios from 'axios'
import { ElMessage } from 'element-plus'
// 响应拦截器
service.interceptors.response.use(
response => {
const { success, message, data } = response.data
// 要根据success的成功与否决定下面的操作
if (success) {
return data
} else {
// 业务错误
ElMessage.error(message) // 提示错误消息
return Promise.reject(new Error(message))
}
},
error => {
// TODO: 将来处理 token 超时问题
ElMessage.error(error.message) // 提示错误信息
return Promise.reject(error)
}
)
export default service
这时,我们需要对 vuex 中的 user 模块进行一下处理
this.commit('user/setToken', data.token)
登录鉴权解决方案
完成上边这些,登录相关的就只剩下鉴权这一部分了,在进行鉴权处理之前我们需要先创建一个登录后的跳转页面
1、创建 layout/index.vue
<template>
<div>Layout 页面</div>
</template>
<script setup>
import {} from 'vue'
</script>
<style lang="scss" scoped></style>
2、在 router/index 中,指定对应的路由表
const publicRoutes = [
{
path: '/',
component: () => import('@/layout/index')
}
]
3、登录后进行跳转
// 登录后操作
router.push('/')
处理完这个页面,我们就开始处理登录鉴权,那么什么是登录鉴权呢
用户未登录时,不允许进入除
login外的其他页面
用户登录后,token未过期前,不允许用户进入login页面
想要实现这个功能,我们需要通过路由守卫进行实现
在 main.js 同级创建 permission.js
import router from './router'
import store from './store'
// 白名单
const whiteList = ['/login']
/**
* 路由前置守卫
*/
router.beforeEach(async (to, from, next) => {
// 存在 token ,进入主页
// if (store.state.user.token) {
// 快捷访问
if (store.getters.token) {
if (to.path === '/login') {
next('/')
} else {
next()
}
} else {
// 没有token的情况下,可以进入白名单
if (whiteList.indexOf(to.path) > -1) {
next()
} else {
next('/login')
}
}
})
此处,我们使用了 vuex 的 getters,使用其进行快捷访问
const getters = {
token: state => state.user.token
}
export default getters
在 store/index 中导入
import getters from './getters'
export default createStore({
getters,
})
最后还需要在 main.js 中引入 permission.js
到这里,整个的登录架构解决方案就已经基本完成了