怎么实现一个登录页面
在api目录下面,建立一个login.js文件, 配置三个发送axios请求的函数并导出
- 获取token
- 使用token兑换info
- 退出登录
// login.js // 获取axios实例request import request from '@/util/request'; // 登录,获取token const reqLogin = (username, password) => request.post('/admin/login', { username, password }); // 使用token兑换info const reqGetInfo = () => request.post('/admin/getinfo'); // 退出登录 const reqLogout = () => request.post('/admin/logout'); // 导出 export { reqLogin, reqGetInfo, reqLogout };
在utils目录里面, 创建一个user.js文件夹, 用来存放一些token工具
- 添加token
- 获取token值
- 移除token
// user.js // 添加token export function setToken(token) { localStorage.setItem('shopAdmin-token', token); } //获取token export function getToken() { return localStorage.getItem('shopAdmin-token'); } // 移除token export function removeToken() { return localStorage.removeItem('shopAdmin-token'); }
在stores目录下面, 新建一个pinia仓库loginStore.js , 用做登录数据的存储库
- state: ①token ②info
- actions: ①获取token ②token兑换info ③登出并删除token和info
// loginStore.js import { defineStore } from 'pinia'; import { setToken, getToken, removeToken } from '@/util/user.js'; import { reqLogin, reqGetInfo, reqLogout } from '@/api/login.js'; export const useLoginStore = defineStore('login', { state: () => { return { token: getToken() || '', info: '', }; }, actions: { // 1. 获取token async getAndSaveToken({ username, password }) { try { const { token } = await reqLogin(username, password); console.log(token); // 存一份到localStorege setToken(token); // 本仓库存一份 this.token = token; } catch (error) { // console.log(error); return Promise.reject(error); } }, // 2.使用token兑换info async getInfoByToken() { try { const info = await reqGetInfo(); this.info = info || {}; } catch (error) { // console.log(error); return Promise.reject(error); } // 3.派发退出登录actions logout() { // 不在意请求的响应结果 reqLogout(); // 清空本仓库的token和info this.token = ''; this.info = {}; // 清空localStorege removeToken(); }, }, });
? 为什么前两个actions都要tryCatch一下, 并返回一个错误的promise?
这是为了别的页面调用这个actions也能tryCatch处理错误
在pages目录下面的单文件组件中, 比如login.vue, 在表单验证成功之后, 处理以下逻辑
- 表单验证通过
- 获取并存储token
- 使用token兑换info
- 去往首页
// login.vue // 引入登录页的store和vue-router import { useLoginStore } from '@/stores/loginStore.js'; import { useRouter } from 'vue-router'; // 创建两个对象 const router = useRouter(); const loginStore = useLoginStore(); ...... 假设上面已经表单校验通过 // 在表单验证成功之后: // 1. 获取并存储token try { await loginStore.getAndSaveToken({ username: form.username, password: form.password, }); } catch (err) { alert('用户名或密码错误'); return; } // 2. 使用token兑换info try { await loginStore.getInfoByToken(); } catch (error) { alert('获取用户信息失败'); return; } // 3. 去往首页 router.push('/');
将token通过请求拦截器, 添加在请求头里面
引入loginStore
通过loginStore获取token
将token添加在请求头中
注意 :尽量从pinia仓库获取token和info数据, 从localStorege获取性能很差
import { useLoginStore } from '@/stores/loginStore.js'; ...... request.interceptors.request.use((config) => { const token = useLoginStore().token; if (token) { // 将token设置在请求头中 config.headers.token = token; } return config; }); ......
配置全局前置守卫
- 定义白名单
- 从loginStore里面获取token和info
- 根据不同情况, 定义不同规则
// 定义白名单页面数组 const whiteList = ['/login']; router.beforeEach(async (to, from, next) => { // 引入登录的store const loginStore = useLoginStore(); // 得到token和info里面的username const token = loginStore.token; const username = loginStore.info.username; // 如果没有token if (!token) { // 是白名单的页面 if (whiteList.includes(to.path)) { // 放行 next(); } else { // 不是白名单页面, 直接回到登录页 alert('请登录!'); next('/login'); } } else { // 如果有token, 想从别的页面去login if (to.path == '/login') { // 不让去登录页 alert('不可直接去登录页,请先退出登录'); next(false); } else { // 如果去的不是登录页 // 如果有info信息 if (username) { next(); } else { try { // 如果没有info信息, 派发actions让仓库重新获取info await loginStore.getInfoByToken(); next(); } catch (error) { // 获取失败,视为token过期 // 派发退出登录action loginStore.logout(); alert('登录状态过期,请重新登录'); next('/login'); } } } } });
上述的路由规则逻辑如下
标签:info,const,登录,实现,loginStore,token,login,页面 From: https://www.cnblogs.com/liucx955/p/project-q-a-zkifo1.html