首页IT科技vue 权限管理(vue3 一个基于pinia简单易懂的系统权限管理实现方案,vue-router动态路由异步问题解决)

vue 权限管理(vue3 一个基于pinia简单易懂的系统权限管理实现方案,vue-router动态路由异步问题解决)

时间2025-08-03 00:48:04分类IT科技浏览5484
导读:前情提要 作为项目经验稀少的vue开发者来说,在关键技术点上的经验不多,我希望通过我的思想和实践,把好的东西分享在这里,目的是进一步促进技术交流。项目即将完成,权限是最后的收尾工作,好的权限实现方案,可以让我们没有后顾之忧,也可以提升项目的运行速度。...

前情提要

作为项目经验稀少的vue开发者来说               ,在关键技术点上的经验不多                       ,我希望通过我的思想和实践       ,把好的东西分享在这里       ,目的是进一步促进技术交流               。项目即将完成                       ,权限是最后的收尾工作               ,好的权限实现方案       ,可以让我们没有后顾之忧                      ,也可以提升项目的运行速度                      。

应用场景

在开发之前               ,我粗略的浏览了一些权限实现方法,可以说智者见智吧                      ,例如一种实现方案是在router的守卫里判断                      ,我认为虽然实现了功能,但是增加了路由的功能压力        。我们的需求是登录后即获知权限               ,根据权限提供功能;根据以上俩点需求我做出了如下计划:

找一个合适的入口                      ,判断要提供的菜单以及用户拥有什么权限       ,不能影响页面加载 在对应的页面中拿到权限               ,提供需要的功能 必须整个系统都可以轻易拿到                       ,且要避免安全问题

实战解析

大多的实现方案是添加路由       ,我也实践了一次       ,发现存在路由重定向问题                       ,于是我准备反其道而行               ,初始提供所有路由       ,根据权限移除不需要的路由                      ,上面我分析到               ,我不想给导航守卫添加过多的压力,避免影响页面渲染                      ,所以我利用了pinia状态库+router.removeRoute来实现路由的控制;

1               、控制添加路由

首先我们应该准备基础的router配置                      ,包括公共页面,异常页面等:

//router/index.js import { createRouter, createWebHistory } from vue-router import { useUsersStore } from "@/store/user"; import Cookies from "js-cookie"; import { isUserTime } from "@/tool/unitl.js" const routes = [ { path: /, name: Index, component: () => import(@/view/Index.vue), }, { path: /login, name: Login, component: () => import(@/view/Login.vue) }, { path: /business, name: Business, component: () => import(@/view/business/Index.vue) }, { path: /business/project, name: BusinessProject, component: () => import(@/view/business/Project.vue) }, { path: /commerce, name: Commerce, component: () => import(@/view/commerce/Index.vue) }, { path: /commerce/project, name: CommerceProject, component: () => import(@/view/commerce/Project.vue) }, { path: /consult, name: Consult, component: () => import(@/view/consult/Index.vue) }, { path: /consult/project, name: ConsultProject, component: () => import(@/view/consult/Project.vue) }, { path: /finance, name: Finance, component: () => import(@/view/finance/Index.vue), children: [ { path: projects/project, name: FinanceProjectsProject, component: () => import(@/view/finance/projects/Project.vue) }, { path: employee/project, name: FinanceEmployeeProject, component: () => import(@/view/finance/employee/Project.vue) }, { path: account, name: FinanceAccount, component: () => import(@/view/finance/account/Index.vue) }, { path: authority/project, name: FinanceAuthority, component: () => import(@/view/finance/authority/Project.vue) } ] }, { path: /chief, name: Chief, component: () => import(@/view/chief/Index.vue), children: [ { path: first_examine/project, name: firstExamineProject, component: () => import(@/view/chief/first_examine/Project.vue) }, { path: second_examine/project, name: secondExamineProject, component: () => import(@/view/chief/second_examine/Project.vue) } ] }, { path: /email, name: Email, component: () => import(@/view/email/Index.vue) }, { path: /person, name: Person, component: () => import(@/view/person/Detail.vue) }, { path: /:pathMatch(.*)*, name: 404, component: () => import(@C/tool/Page404.vue) } ] const router = createRouter({ history: createWebHistory(), //history routes }) router.beforeEach(async (to, from) => { //pinia仓库可以最早出现的地方               ,路由初始化完毕 const store = useUsersStore(); if (to.name == 404 && from.name == Login) { //处理404问题                      ,并且从login跳转任何404页面重置为Login页面 return { name: Login }; } else if (store.isLogin) { //不是404       ,登录状态在               ,正常跳转 return true; } else if (isUserTime() && Cookies.get("loginPwd")) { //刷新进入                       ,判断是否过期了登录时间       ,Cookie中是否存在密码 //如果存在免登录       ,如果登录过程存在路由不存在的问题则404                       ,否则正常跳转 let exist = await store.Login(to); if (!exist) return { name: 404 }; } else return { name: "Login" }; }); export default router

以上代码为router所有前期需要准备的代码               ,已经我处理路由异常情况的实现方案       ,核心是利用:

async await 俩个关键字实现                      ,因为在登录后               ,我们配置移除菜单和权限是需要时间的,必须要严格控制异步                      ,这里也顺便处理了路由输入回车跳转情况                      , 通过await store.Login(to);传入了to的参数来判断如何跳转,接下来参考下我的pinia仓库实现过程; //src/store/user.ts import { defineStore } from pinia import { apiGetUser } from @/axios/user.js import CryptoJS from crypto-js import router from @/router/index.js // 第一个参数是应用程序中 store 的唯一 id export const useUsersStore = defineStore(users, { state: () => { return { isLogin: false, phone: sessionStorage.UserN ? CryptoJS.AES.decrypt( sessionStorage.getItem(UserN), "abc!" ).toString(CryptoJS.enc.Utf8) : , pwd: "", deptno: "", idCard: "", lockState: "", birthday: "", name: "", sex: "男", power: ,//权限:0-admin,1-部门总负责人,2-部门项目负责人,3-部门成员 showMenu: , } }, actions: { Login(to) { let _that = this; let MenuArray = [Business, BusinessProject, Commerce, CommerceProject, Consult, ConsultProject, Finance, Chief]; return new Promise((t, f) => { _that.isLogin = true; let data = new FormData(); data.append(loginAct, _that.phone) apiGetUser(data).then(res => { let { deptno, idCard, lockState, name, sex, birthday } = res, showMenu = deptno.charAt(0); console.log(res); _that.$patch({ deptno, idCard, lockState, name, sex, birthday, showMenu }) if (showMenu == R) { t(true) } else { //过滤菜单项 switch (showMenu) { case A: MenuArray = MenuArray.filter(item => { return item.indexOf(B) == -1 }); break; case B: MenuArray = MenuArray.filter(item => { return item.indexOf(Com) == -1 }); break; case C: MenuArray = MenuArray.filter(item => { return item.indexOf(Con) == -1 }); break; case D: MenuArray = MenuArray.filter(item => { return item.indexOf(F) == -1 }); break; case E: MenuArray = MenuArray.filter(item => { return item.indexOf(Ch) == -1 }); break; } //循环移除 let Length = MenuArray.length; MenuArray.forEach((item, index) => { if (index == Length - 1) { router.removeRoute(item); if(to.name && router.hasRoute(to.name)){ t(true) }else{ t(false) } } else { router.removeRoute(item) } }) } }) }) }, }, })

这里我直接展示了我的代码               ,如果你不熟悉pinia,要抓紧补了                      ,在用户登录验证成功后       ,这里会调用user库的login函数               ,也会携带路由要to的参数                       ,这里只需要明确几个点即可:

MenuArray       ,将来用来循环removeRoute使用的数组       ,映射路由name 根据自己的配置规则                       ,筛选 MenuArray 通过index == Length - 1 严格控制最后一次移除               ,并且判断to.name是否合法 理解await原理       ,await必须出现在async函数中                      ,且 返回函数如果是Promise               ,则只接受resolved中的值; router, 熟悉vue3的同志知道 有一个useRouter 驱动函数,在我们的方案里不能那样使用                      ,因为useRouter必须在setup函数中使用;

2                       、实践观察

我们的需求完美实现                      ,接下来就是把不需要的菜单隐藏掉

3       、控制功能

路由我们已经控制住了,隐藏菜单就很容易了               ,加载userStore 获取条件v-if即可                      ,例如在header组件中:

//header.vue import { useUsersStore } from "@/store/user.js" const user = useUsersStore(); //html <el-menu-item index="/">首页</el-menu-item> <el-menu-item v-if="AR.indexOf(user.showMenu) != -1" index="/business">业务部</el-menu-item> <el-menu-item v-if="BR.indexOf(user.showMenu) != -1" index="/commerce">商务部</el-menu-item> <el-menu-item v-if="CR.indexOf(user.showMenu) != -1" index="/consult">咨询部</el-menu-item> <el-menu-item v-if="DR.indexOf(user.showMenu) != -1" index="/finance">财务部</el-menu-item> <el-menu-item v-if="ER.indexOf(user.showMenu) != -1" index="/chief">总工办</el-menu-item>

这边根据自己团队的权限规范条件处理即可       ,其他的控制举一反三

4       、解决异步路由问题

router.beforeEach(async (to, from) => { //pinia仓库可以最早出现的地方               ,路由初始化完毕 const store = useUsersStore(); if (to.name == 404 && from.name == Login) { //处理404问题                       ,并且从login跳转任何404页面重置为Login页面 return { name: Login }; } else if (store.isLogin) { //不是404       ,登录状态在       ,正常跳转 return true; } else if (isUserTime() && Cookies.get("loginPwd")) { //刷新进入                       ,判断是否过期了登录时间               ,Cookie中是否存在密码 //如果存在免登录       ,登录过程存在路由不存在问题则404                      ,否则正常跳转 let exist = await store.Login(to); if (!exist) return { name: 404 }; } else return { name: "Login" }; });

这里是我项目的路由守卫               ,它已经完成绝大部分功能,登录权限判断                      ,404处理                      ,刷新进入,状态持久化               ,异步操作在网络环境中是无法避免的                      ,router官方示例也明确提醒了我们如何使用       ,这里我们是利用服务器数据判断要移除的菜单               ,且不说http响应异步                       ,router.removeRoute()也只能是一次删除一个       ,所以在store.Login(to)我严格控制了逻辑       ,并且也解决了上述问题,使用我这样的全局守卫来配置必须要理清楚逻辑:依靠 async及await来实现                       ,缺点是会有短暂的延迟               ,还不够流畅       ,但是笔者由于时间问题                      ,不能再优化下去               ,希望大家吸取精华去掉糟粕               。

至此我的分享结束,如果大家有更好的解决方案                      ,希望可以进一步交流                      。

最后

📚 vue专栏

☃️ 个人简介:一个喜爱技术的人        。

🌞 励志格言: 脚踏实地                      ,虚心学习       。

❗如果文章还可以,记得用你可爱的小手点赞👍关注✅               ,我会在第一时间回                       、回访                      ,欢迎进一步交流                      。
声明:本站所有文章       ,如无特殊说明或标注               ,均为本站原创发布               。任何个人或组织                       ,在未征得本站同意时       ,禁止复制               、盗用       、采集                      、发布本站内容到任何网站               、书籍等各类媒体平台       。如若本站内容侵犯了原著者的合法权益       ,可联系我们进行处理                      。

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
pniopcac.exe是什么进程(pcscan.exe是什么进程 pcscan进程查询) dpdk中断模式(dpkg-query命令 – 在dpkg数据库中查询软件包)