vue3权限管理——(路由权限)动态路由设置
1.大概思路
- 设置基础路由login和home等页面;
- 登录后从后端获取user,token,rights等数据,并将数据同时存储到vuex和sessionStorage中
- 将后端获取的权限数据(作为不同用户显示不同菜单及不同路由的依据)和路由页面进行映射;
- 写公共方法添加动态路由;
- 在路由全局守卫中判断是否已添加过动态路由,如果已添加直接next()未添加调用添加动态路由方法,并且放行(next({ ...to, replace: true }););
- 添加动态路由位置第二种方法:全局路由中只负责判断是否有动态路由和放行,调用添加动态路由方法,在登录后立即调用,且以防页面手动刷新时进行404页面,需要在App.vue的create()方法中再次调用
2.设置基础路由,login页面,Home页面等
//route.js
import { createRouter, createWebHistory } from 'vue-router'
const routes = [{ name: 'Login', path: '/login', component: Login },{name: 'Home',path: '/',component: Home,// 到home页面后直接跳转到excelPreview页面redirect: '/uploadSpec?active=0',meta: {authentication: true},// 整个页面为Home,如果想要点击el-aside左侧菜单,将对应路由内容显示在el-main区域,需要将其他路由路径设置为Home的子路径,且path前没有/children: [{name: 'UploadSpec',path: 'uploadSpec',title: '上传spec',component: UploadSpec,// 组件内传参meta: {keepAlive: true,authentication: true,// 用于设置tab名title: '上传spec',}},]},// vue3不再使用path:'*'正则匹配,而是使用/pathMatch(.*)*或/pathMatch(.*)或/catchAll(.*)// { name: 'NotFound', path: '/404', component: NotFound },// { path: '/:pathMatch(.*)', redirect: '/404' },
];const router = createRouter({history: createWebHistory(),routes,
});
2.从后端获取菜单权限数据并设置到vuex和sessionStorage中
这里使用mock模拟后端返回数据
//mock/user.js
import Mock from 'mockjs'const users = [{'id': 1, path:'/uploadSpec','authName': "上传spec", 'icon': '',children:[]},{'id': 2, path:'/showSpec', 'authName': "Spec预览", 'icon': '',children:[]},{'id': 3, path:'/generateTxt', 'authName': "生成测试数据", 'icon': '',children:[]},{'id': 4, path:'/generateCronjob', 'authName': "生成转码程序", 'icon': '',children:[]},{'id': 5, path:'/pdfCompare', 'authName': "PDF文档对比", 'icon': '',children:[]},{'id': 6, path:'/resourceUpdate', 'authName': "资源更新管理", 'icon': '',children:[]},{'id': 7, path:'/generateTestCase', 'authName': "自动生成ST/SIT案例", 'icon': '',children:[]},{'id': 8, path:'/userManagement', 'authName': "用户管理", 'icon': 'User'},
]Mock.mock("/user/login", Mock.mock({"code": 200,"success": true,"data": {users: users,"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwidXNlck5hbWUiOiJhZG1pbiIsIm5pY2tOYW1lIjoi6LaF566hIiwiaWNvbiI6IiIsInJvbGVJZCI6MSwic3ViIjoiYWRtaW4iLCJleHAiOjE2OTI3NzMzNTMsImp0aSI6ImZkNmVkOWZiMjdiYzQxODg5OWRmYmYzNzhlMTMzZmQ0In0.APGpN-i2edKwPQA52LP10aDEM2DZi7G71k8f_njGcpE"}
})
)Mock.mock("/user/me", Mock.mock({"code": 200,"success": true,"data": {"id": 1,"userName": "admin","nickName": "超管","icon": "","roleId": 1,"rights": users,}
})
)
3.登录后将数据存到vuex和sessionStorage中
//Login.vue await this.$store.dispatch("user/login", {...this.user});
//store/user/user.js
import * as api from '@/api/api'
import { ElMessage } from 'element-plus'const state = () => {return {user:JSON.parse(sessionStorage.getItem("user") || '{}'),rights: JSON.parse(sessionStorage.getItem("rights") || '[]')}
}const getters = () => {}const actions = {// 注意async位置和箭头函数写法login: async({ commit }, user) => {// 调用登录接口try {let result = await api.login(user);if (result.data.code === 200) {sessionStorage.setItem("token", result.data.data.token);// 调用获取user信息接口let loginUser = await api.getLoginUser();// 调用mutations的login方法if (loginUser.data.code === 200) {commit('login', loginUser.data.data);} else {ElMessage.error("登录失败:用户信息获取失败");}} else {ElMessage.error("登录失败:" + result.data.errorMsg);}} catch (error) {throw error;}},
}const mutations = {initUser: (state) => {// 从localStorage中获取数据设置进user中,否则通过刷新页面时,获取不到state中的user信息state.user = JSON.parse(sessionStorage.getItem("loginUser"));},login: (state, user) => {// 登录成功后将user信息存到state中,且缓存到localStorage中state.user = user;state.rights = user.rights;sessionStorage.setItem("loginUser", JSON.stringify(user));sessionStorage.setItem("rights", JSON.stringify(user.rights));},
}export default {namespaced: true,state,getters,actions,mutations
}
4.设置菜单权限数据和路由的映射
注意此处routeMapping的key和uploadSpecRule的path以及和后端返回数据rights的user.js的path必须一致;且路径必须有 "/"
const uploadSpecRule = {name: 'UploadSpec',path: '/uploadSpec',title: '上传spec',component: UploadSpec,meta: {keepAlive: true,authentication: true,title: '上传spec',}
};const showSpecRule = {name: 'ExcelPreview',path: '/showSpec',title: 'Spec预览 | 生成测试数据',component: ExcelPreview,meta: {keepAlive: true,authentication: true,title: 'Spec预览',}
};const generateTxtRule = {name: 'GenerateTxt',path: '/generateTxt',title: '生成测试数据',component: GenerateTxt,meta: {keepAlive: true,authentication: true,title: '生成测试数据',}
};
const generateCronjobRule = {name: 'GenerateCronjob',path: '/generateCronjob',title: '生成转码程序',component: GenerateCronjob,meta: {keepAlive: true,authentication: true,title: '生成转码程序',}
};
const pdfCompareRule = {name: 'PDFCompare',path: '/pdfCompare',title: 'PDF文档对比',component: PDFCompare,meta: {keepAlive: true,authentication: true,title: 'PDF文档对比',}
};
const resourceUpdateRule = {name: 'ResourceUpdate',path: '/resourceUpdate',title: '资源更新管理',component: ResourceUpdate,meta: {keepAlive: true,authentication: true,title: '资源更新管理',}
};
const generateTestCaseRule = {name: 'GenerateTestCase',path: '/generateTestCase',title: '自动生成ST/SIT案例',component: GenerateTestCase,meta: {keepAlive: true,authentication: true,title: '自动生成ST/SIT案例',}
};
const userManagementRule = {name: 'UserManagement',path: '/userManagement',title: '用户管理',component: UserManagement,meta: {keepAlive: true,authentication: true,title: '用户管理',}
};const routeMapping = {'/uploadSpec': uploadSpecRule,'/showSpec': showSpecRule,'/generateTxt': generateTxtRule,'/generateCronjob': generateCronjobRule,'/pdfCompare': pdfCompareRule,'/resourceUpdate': resourceUpdateRule,'/generateTestCase': generateTestCaseRule,'/userManagement': userManagementRule,
}
5.设置可导出添加动态路由公共方法
export const initDynamicRoutes = async () => {const rightsList = Store.state.user.rights;;rightsList.length > 0 && rightsList.forEach(item => {if (item.path) {const temp = routeMapping[item.path];router.addRoute("Home", temp);}});router.addRoute( { name: 'NotFound', path: '/404', title:"页面不存在",component: NotFound });router.addRoute( { path: '/:pathMatch(.*)', redirect: '/404' });
}
5.全局路由守卫中鉴权及激活动态路由
注意在vue-router4.X中,动态路由主要通过两个函数实现。router.addRoute()
和 router.removeRoute()
。它们只注册一个新的路由,也就是说,如果新增加的路由与当前位置相匹配,就需要你用 router.push()
或 router.replace()
来手动导航,才能显示该新路由。
也就是说以前的rouer.addRoutes()添加即可使用动态路由的方式不行了
// 路由守卫鉴权处理
router.beforeEach(async (to, from, next) => {let token = sessionStorage.getItem("token");let isToken = !!token;let loginUser = Store.state.user.user;if (isToken) {if (loginUser) {// 如果是login,且已经登录了直接跳转到home页面if (to.name === "Login") return next();// 已经设置过动态路由直接放行,没有则需要通过手动调用 router.replace()进行路由显示if (isDynamic) {next();} else {await initDynamicRoutes();isDynamic = true;next({ ...to, replace: true });}} else {sessionStorage.clear();next("/login");}} else {isDynamic = false;next();}
});
6.第二种方法激活动态路由——在Login.vue和App.vue中调用
这种方式不会每次路由都调用一次添加动态路由方法,个人觉得这种方式性能比较好
//App.vue
import { initDynamicRoutes } from "@/route/route"
export default {name: 'App',created(){initDynamicRoutes();}
}
</scri
//Login.vuetry {await this.$store.dispatch("user/login", {...this.user});//登录成功后,根据用户的rights动态添加路由initDynamicRoutes();this.$router.push({ name: "Home" });} catch (e) {}
7.注意点:
7.1 必须使用router.addRoute()方法进行添加动态路由
添加动态路由方法中,是使用router.addRoute()方法进行添加,Home表示将路由嵌套在Home页面下
rightsList.length > 0 && rightsList.forEach(item => {if (item.path) {const temp = routeMapping[item.path];router.addRoute("Home", temp);}});
我试过之前的添加方法已经不能成功添加动态路由了
const currentRoutes = router.options.routes;rightsList.length > 0 && rightsList.forEach(item => {if (item.path) {const temp = routeMapping[item.path];currentRoutes[1].children.push(temp);}});
7.2 错误页面添加时机
错误页面必须也使用动态添加方法,并且在路由动态添加完成后再添加,否则如果在基础路由中定义错误页面,那么每次点击路由都会首先找路由,没找到就会匹配到错误页面,从而跳转到错误页面
rightsList.length > 0 && rightsList.forEach(item => {if (item.path) {const temp = routeMapping[item.path];router.addRoute("Home", temp);// currentRoutes[1].children.push(temp);}});router.addRoute( { name: 'NotFound', path: '/404', title:"页面不存在",component: NotFound });router.addRoute( { path: '/:pathMatch(.*)', redirect: '/404' });
7.3判断动态路由是否启用的标识
如果直接next()会找不到动态路由,而直接next({ ...to, replace: true });会导致永远去找动态路由
使用标识后,如果有动态路由就加载动态路由,没有直接放行
if (isToken) {if (loginUser) {// 如果是login,且已经登录了直接跳转到home页面if (to.name === "Login") return next();// 已经设置过动态路由直接放行,没有则需要通过手动调用 router.replace()进行路由显示if (isDynamic) {next();} else {// await initDynamicRoutes();isDynamic = true;next({ ...to, replace: true });}} else {sessionStorage.clear();next("/login");}} else {isDynamic = false;next();}
7.4警告:[Vue Router warn]: No match found for location with path "/generateCronjob"
以7.2的方式,在动态添加完其他路由后,再添加错误页面就能成功导到不同路由页面,但是警告依然会存在
相关文章:

vue3权限管理——(路由权限)动态路由设置
1.大概思路 设置基础路由login和home等页面;登录后从后端获取user,token,rights等数据,并将数据同时存储到vuex和sessionStorage中将后端获取的权限数据(作为不同用户显示不同菜单及不同路由的依据)和路由页面进行映射࿱…...

小程序开发之登录授权
小程序开发登录授权流程 看懂这张图登录授权就没问题了(哈哈哈哈哈) 说明: 调用 wx.login() 获取 临时登录凭证code ,并回传到开发者服务器。 调用 auth.code2Session 接口,换取 用户唯一标识 OpenID 和 会话密钥 sess…...

批量根据excel数据绘制折线图
要批量根据Excel数据绘制折线图,可以使用数据处理和图表绘制软件,例如Microsoft Excel或Python中的Matplotlib库。以下是两种方法: 1. 使用Microsoft Excel: - 打开Excel并导入包含数据的工作表。 - 选择需要绘制折线图的数…...

无锁并发:探秘CAS机制的魔力
😊 作者: 一恍过去 💖 主页: https://blog.csdn.net/zhuocailing3390 🎊 社区: Java技术栈交流 🎉 主题: 无锁并发:探秘CAS机制的魔力 ⏱️ 创作时间: 2…...

iOS App签名与重签名:从开发者证书到重新安装运行
前文回顾: iOS脱壳技术(二):深入探讨dumpdecrypted工具的高级使用方法 iOS逆向:越狱及相关概念的介绍 在本文中,我们将详细介绍iOS应用的签名过程,包括开发者证书的种类、证书与App ID、Provisi…...

vue项目,如何修改Element-Plus等UI组件库的样式,三种方式搞定!!!
前言 我们在学习和使用组件库构建页面的时候,时常会遇到这样的问题。 即,尽管组件库已经提供了较多的功能,来帮助我们构建自定义的效果,但有时仍不能使我们满意。 这个时候我们就不得不修改UI库的样式,来达到想要的状…...

httpd协议与apache
1.http 相关概念 HTTP是处于应用层的协议,使用TCP传输层协议进行可靠的传送。因此,需要特别提醒的是,万维网是基于因特网的一种广泛因特网应用系统,且万维网采用的是HTTP(80/TCP)和 HTTPS(443/…...

Go 自学:文件的写入和读取
首先,使用os.Create()函数建立一个文件。 接着,使用io.WriteString()函数将内容写入文件。 最后,使用os.ReadFile()函数读取文件内容。 注意,这里读取的文件内容是data byte,我们需要使用string()函数将其转换为字符串…...

py 项目上线centos
1 服务器py版本 ps -ef|grep python|grep -v grep 2 2.x版本 安装 PyMySQL pip install PyMySQL0.9.3 3 后台运行py文件 nohup python down.py 1 > log.log 2>&1 & 这个命令将 down.py 程序放入后台运行, 同时将 stdout 输出到 log.log 文件中&…...

【git】would clobber existing tag 报错解决
问题 在用vscode的Git去pull代码的时候git弹窗报错,查看报错日志发现以下内容: > git pull --tags origin feature/xxx-2.0.0 From 173.110.11.22:VV-WORK-FE/vv-desktop* branch feature/xxx-2.0.0 -> FETCH_HEAD! [rejected] …...

Python OCR 使用easyocr库将图片中的文章提取出来
Python OCR 使用easyocr库将图片中的文章提取出来 初环境内容步骤一:安装easyocr库步骤二:导入必要的库步骤三:创建OCR阅读器对象步骤四:指定要识别的图片路径步骤五:执行OCR识别并提取文章内容步骤六:遍历…...

门禁系统忘记登入密码,现在更换电脑如何迁移旧电脑门禁系统的数据
环境: ivms-4200 v3.10.0.6_c 问题描述: 门禁系统忘记登入密码,现在更换电脑如何迁移旧电脑门禁系统的数据,旧电脑记住密码,忘了密码和密保了 解决方案: 1.前往海康官网下载4200客户端,在新电脑上安装 …...

初试Eureka注册中心
Eureka是spring cloud中的一个负责服务注册与发现的组件。遵循着CAP理论中的A(可用性)P(分区容错性)。一个Eureka中分为eureka server和eureka client。其中eureka server是作为服务的注册与发现中心。 搭建eureka服务 引入eureka依赖 引入SpringCloud为eureka提供的starter依…...

【趣味随笔】怎么维护自己的电脑?
📢:如果你也对机器人、人工智能感兴趣,看来我们志同道合✨ 📢:不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 📢:文章若有幸对你有帮助,可点赞 👍…...

element 下拉组件获取对象
// 选择数据user:[{name:"小白",id:1,money:"100",love:"蛋糕"},{name:"小黑",id:2,money:"200",love:"奶茶"},{name:"小红",id:3,money:"300",love:"烧烤"},] <div><el…...

IDEA下SpringBoot指定环境、配置文件启动
1、idea下的SpringBoot启动:指定配置文件 Springboot项目有如下配置文件 主配置文件application.yml, 测试环境:application-test.yml 生产环境:application-pro.yml 开发环境:application-dev.yml 1.1.配置文件…...

python可视化matplotlib——绘制正弦和余弦
这是一个使用matplotlib库绘制正弦和余弦函数曲线的代码示例。代码中导入了需要的库,并设置了x轴和y轴的标签字体为华文楷体。然后,使用numpy生成一组x轴上的值t,并使用正弦函数生成对应的y轴值s,再使用余弦函数生成对应的y轴值z。…...

Day48|leetcode 198.打家劫舍、213.打家劫舍II、打家劫舍|||
leetcode 198.打家劫舍 题目链接:198. 打家劫舍 - 力扣(LeetCode) 视频链接:动态规划,偷不偷这个房间呢?| LeetCode:198.打家劫舍_哔哩哔哩_bilibili 题目概述 你是一个专业的小偷,…...

Mysql001:Mysql概述以及安装
前言:本课程将从头学习Mysql,以我的工作经验来说,sql语句真的太重要的,现在互联网所有的一切都是建立在数据上,因为互联网的兴起,现在的数据日月增多,每年都以翻倍的形式增长,对于数…...

如何调用api接口获取到商品数据
要调用API接口获取商品数据,需要进行以下步骤: 1.确定API接口 首先需要确定要使用的API接口,可以通过搜索引擎或者相关文档来查找适合的API接口。以淘宝开放平台为例,可以使用淘宝的商品信息查询API接口来获取商品数据。 2.注册…...

http请求方式过滤器与拦截器的区别
get:获取查询数据(查询)post:数据的提交,新增操作(增加)put:向服务端发送数据、改变信息,侧重点在于对数据的修改操作delete:数据库数据的删除head:一般用来判断类型、根据返回状态确定资源是否存在、资源是否更新以及更新的时间等 过滤器与拦截器的区别…...

大语言模型初学者指南 (2023)
大语言模型 (LLM) 是深度学习的一个子集,它正在彻底改变自然语言处理领域。它们是功能强大的通用语言模型,可以针对大量数据进行预训练,然后针对特定任务进行微调。这使得LLM能够拥有大量的一般数据。如果一个人想将LLM用于特定目的ÿ…...

日常生活小技巧 -- 单位换算
开发过程中经常需要需要单位换算的地方。 可以使用工具进行转换: 工具:单位转换 常用单位: 1、角度转换 1弧度(rad) 180/PI 度(deg) 57.29577951308232 度(deg) 1度…...

利用深度蛋白质序列嵌入方法通过 Siamese neural network 对 virus-host PPIs 进行精准预测【Patterns,2022】
研究背景: 病毒感染可以导致多种组织特异性损伤,所以 virus-host PPIs 的预测有助于新的治疗方法的研究;目前已有的一些 virus-host PPIs 鉴定或预测方法效果有限(传统实验方法费时费力、计算方法要么基于蛋白结构或基因ÿ…...

opencv 车牌号的定位和识别+UI界面识别系统
目录 一、实现和完整UI视频效果展示 主界面: 识别结果界面:(识别车牌颜色和车牌号) 查看历史记录界面: 二、原理介绍: 车牌检测->图像灰度化->Canny边缘检测->膨胀与腐蚀 边缘检测及预处理…...

如何使用CSS实现一个自适应两栏布局,其中一栏固定宽度,另一栏自适应宽度?
聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 使用Float属性⭐ 使用Flexbox布局⭐ 写在最后 ⭐ 专栏简介 前端入门之旅:探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅!这个专栏是为那些对Web开发感…...

【PostgreSQL】导出数据库表(或序列)的结构和数据
导出 PostgreSQL 数据库的结构和数据 要导出 PostgreSQL 数据库的结构和数据,你可以使用 pg_dump 命令行工具。pg_dump 可以生成一个 SQL 脚本文件,其中包含了数据库的结构(表、索引、视图等)以及数据。下面是如何使用 pg_dump 导…...

Arcgis colorRmap
arcgis中colorRmap对应的名称: 信息来源:https://developers.arcgis.com/documentation/common-data-types/raster-function-objects.htm 在arcpy中使用方法: import arcpy cr arcpy.mp.ColorRamp("Yellow to Red")python中 ma…...

[JDK8环境下的HashMap类应用及源码分析] capacity实验
🌹作者主页:青花锁 🌹简介:Java领域优质创作者🏆、Java微服务架构公号作者😄、CSDN博客专家 🌹简历模板、学习资料、面试题库、技术互助 🌹文末获取联系方式 📝 系列文章目录 [Java基础] StringBuffer 和 StringBuilder 类应用及源码分析 [Java基础] 数组应用…...

【自动驾驶】TI SK-TDA4VM 开发板上电调试,AI Demo运行
1. 设备清单 TDA4VM Edge AI 入门套件【略】USB 摄像头(任何符合 V4L2 标准的 1MP/2MP 摄像头,例如:罗技 C270/C920/C922)全高清 eDP/HDMI 显示屏最低 16GB 高性能 SD 卡连接到互联网的 100Base-T 以太网电缆【略】UART电缆外部电源或电源附件要求: 标称输出电压:5-20VDC…...