VUE项目中实现权限控制,菜单权限,按钮权限,接口权限,路由权限,操作权限,数据权限实现
VUE项目中实现权限控制,菜单权限,按钮权限,接口权限,路由权限,操作权限,数据权限实现
- 权限系统分类(RBAC)
- 引言
- 菜单权限
- 按钮权限
- 接口权限
- 路由权限
- 菜单权限方案
- 方案一:菜单与路由分离
- 方案二:菜单和路由都由后端返回
- 路由权限控制(如果后端设计菜单后返回的菜单都挂载到路由上)
- 方案一:初始化即挂载全部路由
- 方案二:按需挂载路由
- 按钮权限方案
- 方案一:使用 `v-if` 判断
- 方案二:通过自定义指令进行按钮权限判断
权限系统分类(RBAC)
引言
在实际项目开发中,权限管理是一个关键功能,用于控制不同用户对系统资源的访问。权限是对特定资源的访问许可,权限控制的目的是确保用户只能访问到被分配的资源。例如,网站管理员可以对网站数据进行增删改查,而普通用户只能浏览
菜单权限
菜单管理涉及定义和管理应用中的导航菜单。不同的用户角色可能会看到不同的菜单项,从而访问不同的功能模块。
按钮权限
不同的用户角色可能享有不同的操作权限,例如管理员可以增删改查,而普通用户只能查看。
接口权限
接口权限通常采用 JWT 形式进行验证。如果请求未通过验证,服务器会返回 401 状态码,客户端则跳转到登录页面重新登录。登录成功后,客户端会拿到 token 并将其存储起来,通过 axios 请求拦截器在每次请求时携带 token。
路由权限
路由权限控制用户可以访问的页面和路径。
菜单权限方案
方案一:菜单与路由分离
前端组件:
{name: "login",path: "/login",component: () => import("@/pages/Login.vue")
}
全局路由卫生
function hasPermission(router, accessMenu) {if (whiteList.includes(router.path)) {return true;}const menu = Util.getMenuByName(router.name, accessMenu);return !!menu.name;
}Router.beforeEach(async (to, from, next) => {if (getToken()) {const userInfo = store.state.user.userInfo;if (!userInfo.name) {try {await store.dispatch("GetUserInfo"); // 获取用户信息await store.dispatch('updateAccessMenu'); // 更新访问菜单if (to.path === '/login') {next({ name: 'home_index' }); // 如果当前路径是登录页,跳转到首页} else {next({ ...to, replace: true }); // 替换当前路径}} catch (e) {if (whiteList.includes(to.path)) {next(); // 如果路径在白名单中,直接通过} else {next('/login'); // 否则跳转到登录页}}} else {if (to.path === '/login') {next({ name: 'home_index' }); // 如果当前路径是登录页,跳转到首页} else {if (hasPermission(to, store.getters.accessMenu)) {Util.toDefaultPage(store.getters.accessMenu, to, routes, next); // 跳转到默认页面} else {next({ path: '/403', replace: true }); // 没有权限,跳转到403页面}}}} else {if (whiteList.includes(to.path)) {next(); // 如果路径在白名单中,直接通过} else {next('/login'); // 否则跳转到登录页}}const menu = Util.getMenuByName(to.name, store.getters.accessMenu);Util.title(menu.title); // 设置页面标题
});Router.afterEach((to) => {window.scrollTo(0, 0); // 滚动条回到顶部
});
优点:
前后端职责分明,前端负责路由定义,后端负责菜单管理。
缺点:
需要维护菜单与路由的对应关系,增加了复杂性。
每次路由跳转都需要进行权限判断
不推荐!!!!!
方案二:菜单和路由都由后端返回
思路: 由后端设计菜单表进行菜单管理,返回给前端后,由前端进行拼接成路由,然后进行挂载到全局路由上,router.addRouter()方法上。进行加载,

后端返回菜单json格式
[{name: "home",path: "/",component: "home"},{name: "userinfo",path: "/userinfo",component: "userInfo"}
]
前端处理逻辑
// 将后端菜单数据转换为路由格式
function generateAsyncRouter(menus) {const asyncRoutes = menus.map(menu => {const route = {path: menu.path,name: menu.menuName,meta: {title: menu.menuName,icon: menu.icon},hidden: menu.hidden}// 处理组件if (menu.menuType === 'content') {// 目录类型route.alwaysShow = trueroute.component = Layoutif (menu.children && menu.children.length > 0) {route.children = generateAsyncRouter(menu.children)}} else if (menu.menuType === 'menu') {// 菜单类型,动态加载组件route.component = loadView(menu.path)}// button类型的不需要生成路由return route})// 添加404页面路由asyncRoutes.push({ path: '*', redirect: '/404', hidden: true })
优点:
前后端高度集成,灵活性高。
缺点:
前后端配合要求更高。
每次路由跳转都需要进行权限判断。
推荐这种用法
路由权限控制(如果后端设计菜单后返回的菜单都挂载到路由上)
方案一:初始化即挂载全部路由
const routerMap = [{path: '/permission',component: Layout,redirect: '/permission/index',alwaysShow: true,meta: {title: '权限管理',icon: 'lock',roles: ['admin', 'editor'] // 标记权限},children: [{path: 'page',component: () => import('@/views/permission/page'),name: 'pagePermission',meta: {title: '页面权限',roles: ['admin'] // 标记权限}},{path: 'directive',component: () => import('@/views/permission/directive'),name: 'directivePermission',meta: {title: '指令权限'// 如果没有设置权限标识,意味着这个页面不需要权限}}]}
];
方案二:按需挂载路由
import router from './router';
import store from './store';
import { Message } from 'element-ui';
import NProgress from 'nprogress'; // 进度条
import 'nprogress/nprogress.css'; // 进度条样式
import { getToken } from '@/utils/auth'; // 从 cookie 获取 tokenNProgress.configure({ showSpinner: false }); // 配置进度条function hasPermission(roles, permissionRoles) {if (roles.includes('admin')) return true; // 管理员权限直接通过if (!permissionRoles) return true;return roles.some(role => permissionRoles.includes(role));
}const whiteList = ['/login', '/authredirect']; // 不需要重定向的白名单router.beforeEach((to, from, next) => {NProgress.start(); // 开始进度条if (getToken()) { // 确定是否有 tokenif (to.path === '/login') {next({ path: '/' });NProgress.done(); // 如果当前页面是仪表盘,不会触发 afterEach 钩子,所以手动处理} else {if (store.getters.roles.length === 0) { // 用户信息store.dispatch('GetUserInfo').then(res => { // 获取用户信息const roles = res.data.roles; // 注意:角色必须是一个数组!例如:['editor','develop']store.dispatch('GenerateRoutes', { roles }).then(() => { // 生成路由router.addRoutes(store.getters.addRouters); // 添加路由next({ ...to, replace: true }); // 替换当前路径,防止留下历史记录});}).catch((err) => {store.dispatch('FedLogOut').then(() => {Message.error(err || '验证失败,请重新登录');next({ path: '/' });});});} else {if (hasPermission(store.getters.roles, to.meta.roles)) {next(); // 有权限,继续跳转} else {next({ path: '/401', replace: true, query: { noGoBack: true }}); // 没有权限,跳转到401页面}}}} else {if (whiteList.includes(to.path)) {next(); // 如果路径在白名单中,直接通过} else {next('/login'); // 否则跳转到登录页NProgress.done(); // 如果当前页面是登录页,不会触发 afterEach 钩子,所以手动处理}}
});router.afterEach(() => {NProgress.done(); // 结束进度条
});
这种是我实现的方式
全局路由上,获取到全部菜单,前端进行路由加载

按钮权限方案
方案一:使用 v-if 判断
优点:
简单直观,易于实现。
缺点:
如果页面较多,每个页面都需要获取用户权限并进行判断,增加复杂性。
方案二:通过自定义指令进行按钮权限判断
自定义指令:
import permissionV from './permission-v';const install = function(Vue) {Vue.directive('permission-v', permissionV)
}if (window.Vue) {window['permission-v'] = permissionVVue.use(install); // eslint-disable-line
}permissionV.install = install
export default permissionV
permission-v.js
import store from '@/store'function checkBtnPermission(el, binding) {const { value } = bindingconst permissions = store.getters && store.getters.userInfo.permissionsif (value && value instanceof Array) {if (value.length > 0) {const permission = valueconst hasPermission = permissions.some(permiss => {return permission.includes(permiss)})if (!hasPermission) {el.parentNode && el.parentNode.removeChild(el)}}} else {throw new Error(`need permissions! Like v-permission="['admin','editor']"`)}
}export default {inserted(el, binding) {checkBtnPermission(el, binding)},update(el, binding) {checkBtnPermission(el, binding)}
}
注册到全局
import permission from '@/directive/permission-v'
// 注册全局指令
Vue.use(permission)
Vue.directive('permission-v', permission)//使用方式 v-permission-v
<el-button v-permission-v="['system:role:add']" type="primary" @click="handleAdd" icon="el-icon-plus">新增角色</el-button>
感兴趣的同学可以关注下,日常更新技术文章和demo示例免费的。

https://bytecodestudio.site/


相关文章:
VUE项目中实现权限控制,菜单权限,按钮权限,接口权限,路由权限,操作权限,数据权限实现
VUE项目中实现权限控制,菜单权限,按钮权限,接口权限,路由权限,操作权限,数据权限实现 权限系统分类(RBAC)引言菜单权限按钮权限接口权限路由权限 菜单权限方案方案一:菜单…...
网站的记住我功能与用户登录持久化
1.先决条件:拿到了后端发的凭证并做了持久化储存 2.在1的基础上,加上一个记住我功能,记住我的体现暂时定为: a.不勾选记住我:在浏览器的对话窗不关闭的情况下,凭证是存在有效的,但关闭了对话框…...
SQL自学,mysql从入门到精通 --- 第 15天,数据导入、导出
数据的导入、导出 -- 查看当前设置的目录路径,限制从数据库服务器读取和写入文件的操作只能在指定的目录中进行,在安全性和文件操作限制方面具有重要意义。rootmysqldb 14:19: [(none)]> SHOW VARIABLES LIKE "secure_file_priv"; -----------------…...
android skia渲染介绍
Android AOSP 的渲染系统主要使用 Skia 图形库。Skia 是一个开源的 2D 图形库,它被广泛应用于 Android 的图形渲染中,负责绘制 UI 元素、文本、图像以及其他 2D 图形内容。 以下是 Android AOSP 中 Skia 的作用和它在渲染系统中的位置: 1. 什…...
【网络安全】服务器安装Docker及拉取镜像教程
文章目录 1. 安装 Docker2. 拉取镜像3. 运行 Ubuntu 容器4. 执行相关操作5. 退出并停止容器1. 安装 Docker # 更新软件包索引 sudo apt update# 安装必要的依赖 sudo apt install -y ca-certificates curl gnupg...
Day87:游戏事件绑定
在游戏开发中,事件绑定是指通过监听和处理用户的输入或其他事件(如鼠标点击、键盘按键、碰撞等),来控制游戏中的行为和流程。事件绑定在游戏中扮演着至关重要的角色,它能够让游戏具备互动性和实时反馈。 今天,我们将学习如何在 Python 中使用 Pygame 进行游戏事件绑定,…...
elementplus 使用日期时间选择器,设置可选范围为前后大于2年且只能选择历史时间不能大于当前时间点
需求:时间选择器可选的时间范围进行限制,-2年<a<2年且a<new Date().getTime()核心:这里需要注意plus版没有picker-options换成disabled-date属性了,使用了visible-change和calendar-change属性逻辑:另设一个参…...
将 AMD Zynq™ RFSoC 扩展到毫米波领域
目录 将 AMD Zynq™ RFSoC 扩展到毫米波领域Avnet XRF RFSoC 系统级模块适用于 MATLAB 的 Avnet RFSoC Explorer 工具箱5G mmWave PAAM 开发平台突破性的宽带毫米波波束成形特征:OTBF103 Mathworks Simulink 模型优化毫米波应用中的射频信号路径 用于宽带毫米波上/下…...
Redis企业开发实战(五)——点评项目之分布式锁Redission与秒杀优化
目录 一、Redisson (一)Redisson基本介绍 (二)Redisson入门 1.引入依赖 2.配置Redisson客户端 3.使用Redission的分布式锁 4.tryLock参数解析 4.1tryLock() 4.2tryLock(long waitTime, TimeUnit unit) 4.3tryLock(long waitTime, long leaseTime, TimeUnit unit) 4…...
IDEA安装离线插件(目前提供了MavenHelper安装包)
目录 1、离线安装方式2、Maven Helper 1、离线安装方式 首先访问 IDEA插件网站 下载离线插件安装包,操作如下: 然后打开IDEA的Settings配置,点击Plugins,点击右侧设置按钮(齿轮),选择Install P…...
LabVIEW 开发航天项目软件
在航天项目软件开发中,LabVIEW 凭借其图形化编程优势被广泛应用。然而,航天项目的高可靠性、高精度及复杂环境适应性要求,使得在使用 LabVIEW 开发时,有诸多关键要点需要特别关注。本文将详细分析在开发航天项目软件时需要重点注意…...
互联网大厂中面试的高频计算机网络问题及详解
前言 哈喽各位小伙伴们,本期小梁给大家带来了互联网大厂中计算机网络部分的高频面试题,本文会以通俗易懂的语言以及图解形式描述,希望能给大家的面试带来一点帮助,祝大家offer拿到手软!!! 话不多说,我们立刻进入本期正题! 一、计算机网络基础部分 1 先来说说计算机网…...
如何定义“破坏环境”
当我们谈论破坏环境时,通常会从人类活动对自然生态造成负面影响的角度来定义。例如,大规模的森林砍伐、工业污染排放、温室气体增加等,都是典型的破坏环境的行为。我们常常看到这些行为导致了生态系统的破坏、物种灭绝、气候变化等问题&#…...
WPS接入DeepSeek模型
1.wps 下载安装 WPS-支持多人在线协作编辑Word、Excel和PPT文档_WPS官方网站 (最好是安装最新的wps) 2.offieceAi工具下载安装 软件下载 | OfficeAI助手 下载后安装下载下来的两个工具。安装路径可以自行修改 3.打开WPS,点击文件-》 选项-》信任中心 勾…...
自然语言处理NLP_[1]-NLP入门
文章目录 1.自然语言处理入门1. 什么是自然语言处理2.自然语言处理的发展简史3 自然语言处理的应用场景1. **机器翻译**2. **文本分类**3. **情感分析**4. **问答系统**5. **文本生成**6. **信息抽取**7. **语音识别与合成**8. **文本摘要**9. **搜索引擎优化**10. **聊天机器人…...
详解在Pytest中忽略测试目录的三种方法
关注开源优测不迷路 大数据测试过程、策略及挑战 测试框架原理,构建成功的基石 在自动化测试工作之前,你应该知道的10条建议 在自动化测试中,重要的不是工具 你是否曾因无关或过时的代码导致测试失败? 这可能会增加调试和故障排除…...
IDEA中列举的是否是SpringBoot的依赖项的全部?在哪里能查到所有依赖项,如何开发自己的依赖项让别人使用
在 IntelliJ IDEA 中列举的依赖项并不一定是 Spring Boot 项目的全部依赖项。IDEA 通常只显示你在 pom.xml(Maven)或 build.gradle(Gradle)中显式声明的依赖项,而这些依赖项本身可能还会引入其他传递性依赖。 1. 如何…...
ECG分析0210
指标计算方法 1. HR (心率,Heart Rate): 心率是每分钟心跳的次数。它通常通过计算RR间期(即两次R波之间的时间间隔)来获得。 计算方法: 首先,检测到R波的位置(例如通过find_peaks函数检测&a…...
计算机毕业设计Python+Spark知识图谱医生推荐系统 医生门诊预测系统 医生数据分析 医生可视化 医疗数据分析 医生爬虫 大数据毕业设计 机器学习
温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 温馨提示:文末有 CSDN 平台官方提供的学长联系方式的名片! 作者简介:Java领…...
JavaScript:CPU缓存预取以及确定数据下直接更改数组length的好处
CPU缓存预取以及确定数据下直接更改数组length的好处 1. CPU 缓存预取(Cache Preloading):CPU 缓存预取:为什么反向填充栈能利用缓存预取: 2. 为什么可以直接改变数组的 length:数组的动态长度:…...
Selenium常用自动化函数
博主主页: 码农派大星. 数据结构专栏:Java数据结构 数据库专栏:数据库 JavaEE专栏:JavaEE 软件测试专栏:软件测试 关注博主带你了解更多知识 目录 1.元素的定位 1.1 定位步骤 1,要想定位,就先打开开发者工具 2,先点击左上角图标 1.2 cssSelector 1.3 xpath 2.操作测…...
【故障排除】ls: command not found 终端命令失效的解决办法
【TroubleShooting】ls: command not found 终端命令失效的解决办法 A Solution to Solve “Command not found” of Terminal on Mac 一直在使用心爱的MacBook Pro的Terminal,并且为她定制了不同的Profile。 这样,看起来她可以在不同季节,…...
OpenStack-Train版-Allinone自动化部署脚本
一、环境准备 操作系统:CentOS 7 或以上版本 建议配置: CPU:8 核或以上 内存:16 GB 或以上 磁盘:500 GB 或以上 网络配置: 确保虚拟机已配置静态 IP 地址 确保虚拟机可以正常访问外部网络 二、自动…...
12.翻转、对称二叉树,二叉树的深度
反转二叉树 递归写法 很简单 class Solution { public:TreeNode* invertTree(TreeNode* root) {if(rootnullptr)return root;TreeNode* tmp;tmproot->left;root->leftroot->right;root->righttmp;invertTree(root->left);invertTree(root->right);return …...
新电脑配置安装下载
1、谷歌浏览器 地址https://www.google.cn/chrome/ 下载安装即可。 2、nvm下载 下载地址:地址https://nvm.uihtm.com/#google_vignette nvm install 相对应的node版本 // 安装 nvm list 可以查看已下载的node版本 // 查看 nvm use 相对应的node版本号 // 使用 nv…...
数字孪生智慧停车管理可视化平台
采用图扑可视化技术搭建智慧停车管理平台,实现了全面的数据整合与实时监控,提升了停车场运营效率和用户体验。通过 HT 可视化界面,管理者能够实时观察和分析停车位使用情况,进行精准调度与优化决策。...
win10 llamafactory模型微调相关②
微调 使用微调神器LLaMA-Factory轻松改变大语言模型的自我认知_llamafactory 自我认知-CSDN博客 【大模型微调】使用Llama Factory实现中文llama3微调_哔哩哔哩_bilibili 样本数据集 (数据集管理脚本处需更改,见报错解决参考1) 自我认知微…...
车载测试工具 --- CANoe VH6501 进行Not Acknowledge (NAck) 测试
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 简单,单纯,喜欢独处,独来独往,不易合同频过着接地气的生活,除了生存温饱问题之外,没有什么过多的欲望,表面看起来很高冷,内心热情,如果你身…...
Mysql中存储引擎各种介绍以及应用场景、优缺点
概述 MySQL 提供了多种存储引擎,每种引擎有不同的特点和适用场景。以下是几种常见的 MySQL 存储引擎的详细介绍,包括它们的底层工作原理、优缺点,以及为什么 MySQL 默认选择某种引擎。 1. InnoDB 底层工作原理: 事务支持&#…...
使用 AlexNet 实现图片分类 | PyTorch 深度学习实战
前一篇文章,CNN 卷积神经网络处理图片任务 | PyTorch 深度学习实战 本系列文章 GitHub Repo: https://github.com/hailiang-wang/pytorch-get-started 本篇文章内容来自于 强化学习必修课:引领人工智能新时代【梗直哥瞿炜】 使用 AlexNet 实现图片分类…...
