vue3+pinia用户信息持久缓存(token)的问题
对博主来说,这是个相当复杂的问题。
当初在使用vue2+vuex进行用户信息持久登录时,写了不下3篇博客,确实是解决了问题,博客链接如下
- vue存储和使用后端传递过来的token
- vue中对token的有效期的理解
- vuex刷新页面丢失登录的token信息的解决方案
第一篇博客是记录前端如何使用token,简言之,就是先把后端传过来的token写入到浏览器的localstorage缓存中,前端在处理路由之前,先检查localstorage中有没有token,有token就放行,没有token就跳转到登录界面
第二篇博客是发现token过期后的处理方式,最后我的vue2项目都没有使用这篇博客中的解决方案,而是使用了第三篇博客的解决方案
第三篇博客出现的问题是,**每次刷新页面,store里面的数据没了,而localstorage中还有数据,**这样的话,页面上有些地方需要store的数据就加载不出来了,但token并没有更新,出现了逻辑错误。解决方案就是每次在启动页面的时候,检查一下localstorage中有没有数据,有数据的话,重新设置一下store,当然,在路由守卫环节也添加了路由的放行规则
我把第三种方案当做终极解决方案,确实很长一段时间都没有再受到困扰
知道我现在开始使用vue3+pinia来写前端项目,问题又来了
pinia和vuex遇到的问题是一样的,我尝试用第三篇博客来解决,按道理应该是可以解决的,但实际上一直没能解决。折腾很长一段时间,找到了一种比较折中的解决方案
pinia-plugin-persistedstate持久化存储数据
实际上就是使用这个pinia-plugin-persistedstate
插件,它解决的问题是,帮你把store中的数据持久化的存储在localstorage中,并且比较好的一点是,当你需要使用store中的数据时,它又从localstorage中取出来给你去渲染页面,其实就和我上面第3篇博客的内容差不多,这样就不怕刷新页面了,先来看看怎么写和怎么中
store文件的写法
直接看代码:
import { ref } from "vue";
import { defineStore } from "pinia";
import { loginAPI } from "@/apis/user";
export const useUserStore = defineStore(
"user",
() => {
const userInfo = ref({});
const getUserInfo = async (data) => {
const res = await loginAPI(data);
// console.log(res);
userInfo.value = res;
// console.log(userInfo.value)
};
// 解决刷新页面丢失store信息的问题
const clearUserInfo = () => {
userInfo.value = {};
localStorage.removeItem('user')
};
return {
userInfo,
getUserInfo,
clearUserInfo,
};
},
{
persist: true,
}
);
pinia用的组合式api写法
- userInfo是用户信息
- getUserInfo是通过调用登录接口,修改userInfo
- clearUserInfo是清除用户信息
在代码的最后面,加了个对象persist: true
,之后每次登录,就会在localstorage中生成一个key为user的字符串对象,刷新页面而这个对象不会消失,模板上需要渲染的时候,又把内容添加给store,相对来说比较靠谱。命名规则就是definstore时定义的变量名。
在我没有添加路由守卫规则之前,这么写的话,会有个问题,退出登录后,还能返回到原来的路由,只是页面上该有的用户信息都没有了,因为clearUserInfo
并没有删除localstorage中的user对象,user一直都在,那按照之前的逻辑,当然行不通了
退出登录时的操作
看看具体怎么解决吧
//这是退出登录用到的方法
const logout = () => {
// userStore.clearUserInfo()
localStorage.removeItem('user')
router.push('/login')
}
其实就是清除localstorage中的user对象
路由守卫
路由守卫是最麻烦的地方,逻辑理不清楚,就没法正常跳转
我的写法
// 路由守卫
import jwt_decode from "jwt-decode";
router.beforeEach((to, from, next) => {
const isLogin = localStorage.user ? true : false;
if (isLogin) {
const user = JSON.parse(localStorage.user)
const decode = jwt_decode(user.userInfo.token);
const date = parseInt(new Date().getTime() / 1000);
if (date - decode.iat > decode.exp - decode.iat) {
localStorage.removeItem("user");
next("/login");
}
}
if (to.path == "/login") {
next();
} else {
isLogin ? next() : next("/login");
}
});
还是根据localstorage中是否有user对象来判断是否登录,但是前面说过了,它存在localstorage中的是一个字符串,大体是下面这个样子
可以看出来,里面有你定义的state数据,所以,需要解析先成json才能正常取值,取值后,就是解析其中的token了,解析完token,就可以判断有没有过期来清除token了
总之,过程相当繁琐,希望不要再写第5篇了。