登录业务实现:
登录成功/失败实现 -> pinia管理用户数据及数据持久化 -> 不同登录状态的模板适配 -> 请求拦截器携带token(登录鉴权) -> 退出登录实现 -> token失效(401响应拦截)
1. 登录成功/失败实现
当表单校验通过时,封装登录接口,调用登录接口,分别处理 登录成功和登陆失败的情况。
登录成功,则提示用户,并跳转首页;
登录失败,报错。-> 拦截器统一报错(配置一次 多接口生效)
2. pinia管理用户数据及数据持久化
因为用户数据可能在多组件中进行共享,使用 pinia对用户数据进行管理。与数据有关的操作置于pinia中,组件只负责触发action函数
(1) pinia管理数据
// 定义store
export const useUserStore = defineStore('模块名', ()=>{
// 1. 定义state
const userInfo = ref({})
// 2. 定义action
const getUserInfo = () => {
...
}
// 3. 以对象的形式return state/action
return {
...
}
})
// 使用store
import { useXXXStore } from '@/stores/XXXStore'
const xxXStore = useXXXStore()
xxXStore.getXX()
(2)持久化用户数据
token:用户数据中 用于标识当前用户是否登录,持续一段时间会过期。
由于pinia是基于内存的,刷新会丢失,为保持登陆状态(刷新不丢失),要配合持久化进行存储
-> 操作state时,自动把用户数据在本地的localStore中也存一份,(刷新时 从localStore中先取)
操作步骤:
1)安装插件包: npm i pinia-plugin-persistedstate
2)注册插件:
// main.js 入口文件中 const pinia = createPinia() pinia.use(piniaPluginPersistedState)
3)持久化配置 存入localStore:
// 定义store中,添加配置项(第三个参数),用于持久化配置 defineStore('',()=>{ ... },{ // 持久化配置,存入ls persist:{ enabled: true } })
3. 不同登录状态的模板适配(多模板适配)
多模板适配 思路:登录时显示第一块,非登录时显示第二块
判断条件:是否有token
<template v-if="userStore.userInfo.token">
...
</template>
<template v-else>
...
</template>
4. 请求拦截器携带token
token作为用户标识,多个接口要正确携带token才能正确显示数据 -> 在接口调用时携带token -> 采用拦截器携带(便于 统一控制)
解决: 请求拦截器可以在接口发起前 对请求参数进行操作。通常token被注入到请求header中,格式按照后端要求的格式进行拼接
// utils/http.js中
// axios请求拦截器
httpInstance.interceptors.request.use(config => {
// 请求拦截器携带token(->按后端要求拼接token数据),使得多个接口携带token
const userStore = useUserStore()
const token = userStore.userInfo.token
if(token){
config.headers.Authorization = `Bearer ${token}` //按后端的要求拼接
}
return config
},e => Promise.reject(e))
5. 退出登录实现
点击退出登录时,防止误触,弹出一个气泡确认框(el-popconfirm)进行二次确认。
退出登录业务逻辑: 清除用户数据;跳转到登录页
// 组件中,views/XXX.vue
<el-popconfirm @confirm="confirm" title="确认退出吗?" confirm-button-text="确认" cancel-button-text="取消">
<template #reference>
<a href="javascript:;">退出登录</a>
</template>
</el-popconfirm>
// store中(stores/XXX.js),定义清除用户信息的action
const clearUserInfo = ()=>{
userInfo.value = {}
}
return {
clearUserInfo
}
...
// 组件中(views/XXX.vue),实现退出登录业务的逻辑
import { useRouter } from 'vue-router'
const router = useRouter()
const confirm = ()=>{
userStore.clearUserInfo() // 1. 清除用户数据( -> 调用action进行操作)
router.push('/login') // 2. 转到登录页
}
6. token失效(401拦截)
token有效性保持一段时间,如果用户不做任何操作,token会失效,使用失效的token去请求一些接口,接口就会报401状态码错误。
解决:在axios响应拦截器做统一处理
// 401拦截
import router from '@/router' //js中的路由对象!!
// axios响应式拦截器中
httpInstance.interceptors.response.use(res => res.data, e => {
const userStore = useUserStore()
...
// 401失效处理: 1.清除用户数据 2. 跳转
if(e.response.status === 401){
userStore.clearUserInfo()
router.push('/login')
}
return Promise.reject(e)
})
export default httpInstance
参考:Popconfirm 气泡确认框 | Element Plus
ElementUI 教程 - Popconfirm 气泡确认框
一文教你搞定所有前端鉴权与后端鉴权方案,让你不再迷惘 - 掘金 (juejin.cn)