企业级Vue路由角色权限应该怎么做?

角色权限

角色权限,简单来说就是登录的用户能看到系统的哪些页面,不能看到系统的哪些页面。一般是后台管理系统才会涉及到如此复杂的角色权限。

对于 vue 技术栈,实现角色权限一般有两种方式。

第一种是利用 beforeEach 全局前置守卫。

第二种是利用 addRoutes 方法。

我们先来看看第一种

通过 beforeEach 实时监测用户权限

这种方案的核心就是首先在 routes 里面事先定义好路由的权限,然后在 beforeEach 全局前置守卫里面进行权限逻辑判断。看用户所拥有的角色和我们配置在路由里面的 roles 是否相匹配。匹配则允许进入,不匹配则重定向到无权限提示页面。

定义 routes

首先我们定义好系统的路由,对于非首页,我们一般都会使用路由懒加载。

在 meta 里面可以定义我们需要的元数据,这里需要加上我们路由的角色roles。也就是说进入该路由用户所需要具备的角色权限。如果没定义则代表任意角色都能进入。

js
复制代码
// router/routes.jsimport Home from "../views/Home.vue";const routes = [{path: "/",name: "Home",component: Home,meta: {needLogin: false, // 不需要登录title: "首页",},},{path: "/about", name: "About",component: () =>import(/* webpackChunkName: "about" */ "../views/About.vue"), // 路由懒加载meta: {needLogin: true, // 需要登录title: "关于",roles: ["admin", "manage"], // 该页面只有admin和普通管理员才能进入},},{path: "/nopermission", // 没权限就进入该页面name: "NoPermission",component: () =>import(/* webpackChunkName: "nopermission" */ "../views/NoPermission.vue"), // 路由懒加载meta: {needLogin: true, // 需要登录title: "暂无权限",},},{path: "/userlist", name: "UserList",component: () =>import(/* webpackChunkName: "userlist" */ "../views/UserList.vue"), // 路由懒加载meta: {needLogin: true, // 需要登录title: "用户管理",roles: ["admin"], // 该页面只有admin才能进入},},{path: "/login",name: "Login",component: () =>import(/* webpackChunkName: "login" */ "../views/Login.vue"), // 路由懒加载meta: {needLogin: false, // 不需要登录title: "登录",},},
];export default routes;

实例化 Router

然后创建路由,vue2vue3创建路由的时候稍有区别,但是在路由鉴权那块是通用的。

js
复制代码
// router/index.js// vue2 写法
import VueRouter from "vue-router";
import routes from "./routes"const router = new VueRouter({mode: "history",base: process.env.BASE_URL,routes,
});// vue3 写法
import { createRouter, createWebHistory } from "vue-router";
import routes from "./routes"const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes,
});

定义路由拦截鉴权逻辑

创建好路由后,我们可以来定义路由拦截的逻辑了,主要通过 beforeEach 全局前置守卫。因为只要页面发生跳转都会进入 beforeEach 全局前置守卫。

这里的核心逻辑就是判断前往的页面是否需要登录,需要登录就进一步判断当前系统是否有token,没有token则重定向到登录页

如果有token,则进一步判断是否有用户信息,如果没有用户信息就获取用户信息

有了用户信息后再判断进入页面需要的角色是否和用户信息里面的角色相匹配,匹配则进入页面,不匹配则进入系统的无权限提示页面。

js
复制代码
// router/index.js// vue2和vue3通用
router.beforeEach(async (to, from, next) => {// 如果需要登录if (to.meta.needLogin) {// 获取tokenconst token = localStorage.getItem("token");// 如果有token 则直接放行if (token) {// 获取用户信息,从store里面获取let userInfo = store.getters["getUserInfo"];// 如果没有用户信息就获取用户信息if (!userInfo) {userInfo = await store.dispatch("getUserInfoAction");}// 如果页面需要权限,并且用户角色不满足则去无权限提示页if (to.meta.roles && !to.meta.roles.includes(userInfo.role)) {return next("/nopermission");}next();} else {// 否则去登录页next("/login");}} else {// 不需要登录则直接放行next();}
});// 修改标题的工作可以放在全局后置守卫
router.afterEach((to, from) => {if (to.meta.title) {document.title = to.meta.title;}
});

我们再来看看 store 的逻辑

js
复制代码
import { createStore } from "vuex";export default createStore({state: {userInfo: null,},getters: {getUserInfo: (state) => state.userInfo,},mutations: {setUserInfo(state, payload) {state.userInfo = payload;},},actions: {async getUserInfoAction({ commit }) {// 模拟后端获取用户信息的apiconst getUserInfoApi = () => {return Promise.resolve({ role: "manage", name: "jack" }); // 假设角色为 manage};const userInfo = await getUserInfoApi();commit("setUserInfo", userInfo);return userInfo;},},
});

使用

创建完路由后需要在 main.js 导入使用

js
复制代码
import router from "./router";// vue2写法
new Vue({router,render: (h) => h(App),
}).$mount("#app");// vue3写法
const app = createApp(App);
app.use(router).mount("#app");

在没登录的情况下,去aboutuserlist页面都会重定向到登录页。

给本地添加token 模拟登录完成后,因为用户信息角色是 manage,所以去 about 是没问题的,去 userlist 则会重定向到没有权限页面。

总结

优点:

实现简单,路由的权限在 meta 的 roles 里面配置。用户信息里面只需要包含当前用户的角色。

缺点:

系统所拥有的角色必须事先知道,然后以死代码的形式配置在 routes 里面,不支持动态添加角色。适用于小型角色固定的系统。

通过 addRoutes 动态添加路由

这种方案的核心就是调用后端接口,返回当前用户角色所拥有的菜单,格式化成路由后通过 addRoutes 将这些路由动态添加到系统。

定义 routes

因为路由从后端获取,所以这里我们只需要定义基本通用路由,也就是不涉及到权限的路由。比如登录页、没权限页、首页。

js
复制代码
import Home from "../views/Home.vue";const routes = [{path: "/",name: "Home",component: Home,meta: {title: "首页",},},{path: "/nopermission", // 没权限就进入该页面name: "NoPermission",component: () =>import(/* webpackChunkName: "nopermission" */ "../views/NoPermission.vue"), // 路由懒加载meta: {title: "暂无权限",},},{path: "/login",name: "Login",component: () =>import(/* webpackChunkName: "login" */ "../views/Login.vue"), // 路由懒加载meta: {title: "登录",},},
];export default routes;

实例化 Router

然后创建路由,vue2vue3创建路由的时候稍有区别。

js
复制代码
// router/index.js// vue2 写法
import VueRouter from "vue-router";
import routes from "./routes"const router = new VueRouter({mode: "history",base: process.env.BASE_URL,routes,
});// vue3 写法
import { createRouter, createWebHistory } from "vue-router";
import routes from "./routes"const router = createRouter({history: createWebHistory(process.env.BASE_URL),routes,
});

定义路由拦截鉴权逻辑

创建好路由后,我们就可以定义动态添加路由的逻辑啦。

这里的核心逻辑就是判断前往的页面是否在白名单内,不在白名单就进一步判断当前系统是否有token,没有token则重定向到登录页

如果有token,则进一步判断是否有用户菜单信息,如果没有用户菜单信息就获取用户菜单信息

有了用户菜单信息后,就先将菜单信息转换成前端路由需要的格式,然后通过addRoutes方法将路由动态添加到系统。

当用户前往不存在的路由时,路由的 name 属性会是 undefined,因此就重定向到无权限提示页面

js
复制代码
// router/index.js// vite创建的项目 使用这种方法实现动态加载
const modules = import.meta.glob("../views/*.vue");// 转换成 vue-router 需要的格式
const transformRoute = (menus) => {return menus.map((menu) => {return {path: menu.path,name: menu.name,component: modules[menu.component],meta: {title: menu.title,},};});
};// vue3需要手动实现该方法
const addRoutes = (routes) => {routes.forEach((route) => {router.addRoute(route);});
};// 白名单页面,不需要权限
const whiteLists = ["/login", "/"];router.beforeEach(async (to, from, next) => {// 是否是白名单if (!whiteLists.includes(to.path)) {// 获取tokenconst token = localStorage.getItem("token");// 如果有tokenif (token) {// 获取用户菜单信息,从store里面获取let userMenus = store.getters["getUserMenus"];// 如果没有用户菜单信息就获取用户菜单信息if (!userMenus) {userMenus = await store.dispatch("getUserMenuAction");// 菜单转成路由const userRoute = transformRoute(userMenus);// 动态添加路由 vue2 和 vue3 有细微差别// vue2// router.addRoutes(userRoute)// vue3// 因为 vue3 移除了 router.addRoutes()方法,所以需要手动实现addRoutes方法。addRoutes(userRoute);return next({ ...to });}// 有name说明路由存在,否则说明没有该路由if (to.name) {next();} else {// 去无权限页面next("/nopermission");}} else {// 否则去登录页next("/login");}} else {// 是白名单则直接进入next();}
});// 修改标题的工作可以放在全局后置守卫
router.afterEach((to, from) => {if (to.meta.title) {document.title = to.meta.title;}
});

我们再来看看 store 的逻辑

js
复制代码
import { createStore } from "vuex";export default createStore({state: {userMenus: null,},getters: {getUserMenus: (state) => state.userMenus,},mutations: {setUserMenus(state, payload) {state.userMenus = payload;},},actions: {async getUserMenuAction({ commit }) {// 模拟后端获取用户菜单信息apiconst getUserMenuApi = () => {// 假设只有about菜单return Promise.resolve([{path: "/about",name: "About",component: "../views/About.vue",title: "关于",},]);};const userMenus = await getUserMenuApi();commit("setUserMenus", userMenus);return userMenus;},},
});

使用

创建完路由后需要在 main.js 导入使用

js
复制代码
import router from "./router";// vue2写法
new Vue({router,render: (h) => h(App),
}).$mount("#app");// vue3写法
const app = createApp(App);
app.use(router).mount("#app");

在没登录的情况下,去aboutuserlist页面会重定向到登录页。

给本地添加token,模拟登录完成后,因为用户有about的菜单,所以去 about 页面是没问题的,去 userlist 页面则会重定向到没有权限页面。

总结

优点:

系统角色可以不固定,支持动态添加角色。适用于后台大型管理系统。

缺点:

实现相对复杂,而且需要后端配合的更多。

总结

第一种通过 beforeEach 实时监测用户权限的方式优势是实现简单,路由的权限在 meta 的 roles 里面配置。用户信息里面只需要包含当前用户的角色。缺点呢也很明显,系统所拥有的角色必须事先知道,然后以死代码的形式配置在 routes 里面,不支持动态添加角色。笔者觉得如果是做角色固定的系统是非常好的,比如什么图书管理系统、教师管理系统等。

第二种通过 通过 addRoutes 动态添加路由实现角色权限的方式优势是系统角色可以不固定,支持动态添加角色。很适用于后台大型管理系统,可以实时创建角色分配菜单。

当然、缺点就是实现起来比较复杂,需要后端一起参与设计。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/23767.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

css中的bfc是什么?

什么bfc? BFC(Block Formatting Context)块级 格式化 上下文。 BFC就是页面上的一个隔离的独立盒子,容器里面的子元素和外面的元素不会相互影响。 为什么要bfc? bfc是我们去主动触发的,并不是自动就存在的,它是帮助我们解决cs…

【雕爷学编程】MicroPython动手做(28)——物联网之Yeelight 2

知识点:什么是掌控板? 掌控板是一块普及STEAM创客教育、人工智能教育、机器人编程教育的开源智能硬件。它集成ESP-32高性能双核芯片,支持WiFi和蓝牙双模通信,可作为物联网节点,实现物联网应用。同时掌控板上集成了OLED…

数据库与数据仓库的区别及关系

数据库与数据仓库的区别及关系 数据库数据仓库异同差异联系例子 数据库 数据库是结构化信息或数据的有序集合,一般以电子形式存储在计算机系统中。通常由数据库管理系统 (DBMS) 来控制。它是一个长期存储在计算机内的、有组织的、可共享的、统一管理的大量数据的集…

任务 13、MidJourney种子激发极致创作,绘制震撼连贯画作

13.1 任务概述 通过本次实验任务,学员将深入了解Midjourney种子的概念和重要性,以及种子对生成图像的影响。他们将学会在Midjourney平台中设置种子值并调整其参数,以达到所需的效果。此外,任务还详细介绍了Midjourney V4.0版本中…

openSUSE安装虚拟化 qemu kvm

1) 第一种:图形界面yast安装虚拟化 左下角开始菜单搜索yast 点一下就能安装,是不是很简单呢 2)第二种: 命令行安装 网上关于openSUSE安装qemu kvm的教程比较少,可以搜索centos7 安装qemu kvm的教程,然后…

ZAFUACM - 23.8.5个人赛补题

文章目录 A - Lucky Conversion题意思路代码 B - Constanzes Machine题意思路代码 C - Maximum Median题意思路代码 D - Remove Extra One题意思路代码 E - A Determined Cleanup题意思路代码 F - Minimal k-covering A - Lucky Conversion 原题链接 题意 给出两个只包含“4…

vue3登录页面

使用了element-plus <template><div class"login-wrapper"><!-- 背景图或者视频 --><div class"background" style"width: 100%; height: 100%; position: absolute; top: 0px; left: 0px;overflow: hidden;z-index:50;&qu…

vue-baidu-map-3x 使用记录

在 Vue3 TypeScript 项目中&#xff0c;为了采用 标签组件 的方式&#xff0c;使用百度地图组件&#xff0c;冲浪发现了一个开源库 ovo&#xff0c;很方便&#xff01;喜欢的朋友记得帮 原作者 点下 star ~ vue-baidu-map-3xbaidu-map的vue3/vue2版本&#xff08;支持v2.0、v…

使用LLM插件从命令行访问Llama 2

大家好&#xff0c;最近的一个大新闻是Meta AI推出了新的开源授权的大型语言模型Llama 2&#xff0c;这是一项非常重要的进展。Facebook最初的LLaMA模型于今年2月发布&#xff0c;掀起了开源LLM领域的创新浪潮——从微调变体到从零开始的再创造。 如果在Llama 2版本发布之日&a…

《面试1v1》ElasticSearch 和 Lucene

&#x1f345; 作者简介&#xff1a;王哥&#xff0c;CSDN2022博客总榜Top100&#x1f3c6;、博客专家&#x1f4aa; &#x1f345; 技术交流&#xff1a;定期更新Java硬核干货&#xff0c;不定期送书活动 &#x1f345; 王哥多年工作总结&#xff1a;Java学习路线总结&#xf…

DLA 神经网络的极限训练方法:gradient checkpointing

gradient checkpointing 一般来说&#xff0c;训练的过程需要保存中间结果&#xff08;不管是GPU还是CPU&#xff09;。前向传播根据输入(bottom_data)计算输出(top_data)&#xff0c;后向传播由top_diff计算bottom_diff&#xff08;如果某个变量打开梯度进行训练的话&#xff…

Vue 动态引入外部js文件

场景 最近在做项目优化时&#xff0c;发现一个特殊依赖&#xff0c;全局只有一个页面会用到。这个依赖很大&#xff0c;而且这个页面极少有人会打开&#xff08;隐藏页&#xff0c;留给开发或交付人员调试使用的&#xff09;。 那么我们考虑通过引入外部js的形式来处理&#…

5个顶级的开源有限元分析软件

每当我参加数值分析课程的教学时&#xff0c;都会回顾有限元方法的基础知识&#xff0c;很自然地就会出现使用哪种软件的问题。 以下讨论基于三个基本考虑&#xff1a; 在实际应用中&#xff0c;很少有人从头开始编写 FEM 代码。商业 FEM 软件通常在某些预定义的情况下非常易于…

使用 Habana Gaudi2 加速视觉语言模型 BridgeTower

&#x1f917; 宝子们可以戳 阅读原文 查看文中所有的外部链接哟&#xff01; 在对最先进的视觉语言模型 BridgeTower 进行微调时&#xff0c;使用 Optimum Habana v1.6&#xff0c; Habana Gaudi2 可以达到 近 3 倍于 A100 的速度。硬件加速的数据加载以及 fast DDP 这两个新特…

luajit 使用 clang编译的坑

为了尝试将LuaJIT接入虚幻Lua插件之中&#xff0c;需要预编译LuaJIT链接库&#xff0c;在桌面平台问题不大, 主要是移动平台&#xff0c;涉及跨平台编译&#xff0c;因为对跨平台编译具体细节没有系统研究&#xff0c;这里先记录一下跨平台编译LuaJIT的主要过程 由于官方提供的…

Pandas操作Excel

Pandas 是 Python 语言的一个扩展程序库&#xff0c;用于数据分析。 菜鸟教程&#xff1a;https://www.runoob.com/pandas/pandas-tutorial.html 读取Excel pd.read_excel(path,sheet_name,header) path&#xff1a;excel文件路径sheet_name&#xff1a;读取的sheet&#xff0…

3.netty和protobuf

1.ChannelGroup可以免遍历由netty提供,覆盖remove方法即可触发删除channel\ 2.群聊私聊 13.群聊私聊简单原理图 3.netty心跳检测机制,客户端对服务器有没有读写(读,写空闲) //IdleStateHandler(3,5,7,TimeUnite.SECONDS)是netty提供的检测状态的处理器,也加到pipeline,读,写,…

【新版系统架构补充】-嵌入式软件

嵌入式软件 嵌入式软件是指应用在嵌入式计算机系统当中的各种软件&#xff0c;除了具有通用软件的一般特性&#xff0c;还具有一些与嵌入式系统相关的特点&#xff0c;包括&#xff1a;规模较小、开发难度大、实时性和可靠性要求高、要求固化存储。 嵌入式软件分类&#xff1…

react Ref 的基本使用

类组件中使用ref 在类组件中&#xff0c;你可以使用createRef来创建一个ref&#xff0c;并将它附加到DOM元素或类组件实例上。使用ref允许你在类组件中访问和操作特定的DOM元素或类组件实例。 下面是在类组件中使用ref的步骤&#xff1a; 引入React和createRef&#xff1a; …

浅析 C 语言的共用体、枚举和位域

前言 最近在尝试阅读一些系统库的源码&#xff0c;但是其中存在很多让我感到既熟悉又陌生的语法。经过资料查阅&#xff0c;发现是 C 语言中的共用体和位域。于是&#xff0c;趁着课本还没有扔掉&#xff0c;将一些相关的知识点记录在本文。 文章目录 前言共用体 (union)枚举…