前端实现动态路由(前端控制全部路由,后端返回用户角色)

优缺点
优点:
- 不用后端帮助,路由表维护在前端
- 逻辑相对比较简单,比较容易上手
- 权限少的系统用前端鉴权更加方便
缺点:
- 线上版本每次修改权限页面,都需要重新打包项目
- 大型项目不适用
- 如果需要在页面中增加角色并且控制可以访问的页面,则不能用前端鉴权
具体思路
1、前端定义静态路由和动态路由,创建vue实例的时候vue-router挂载静态路由(登录等不需要权限的页面)
2、登录时获取用户信息,存入vuex中,存储token
3、在路由拦截器中,通过token去获取用户角色,拿角色去获取所有可访问的路由
4、调用router.addrouters(store.state.addRouters)添加可访问的路由
5、退出时清空用户信息,清空角色,清空路由
步骤一:前端定义静态路由和动态路由
router/index.js
import Vue from "vue"
import VueRouter from "vue-router"
import Layout from "@/layout"Vue.use(VueRouter)// 解决重复点击路由报错的BUG
// 下面这段代码主要解决这个问题 :Uncaught (in promise) Error: Redirected when going from "/login" to "/index" via a navigation guard.
const originalPush = VueRouter.prototype.push
VueRouter.prototype.push = function push(location) {return originalPush.call(this, location).catch((err) => err)
}// 定义好静态路由
export const constantRoutes = [{path: "/login",name: "login",component: () => import("../views/login"),hidden: true,},
]// 定义动态路由,以及每个页面对应的roles(写在meta中,不写代表都可以访问)
export const asyncRoutes = [{id: 1,name: "/",path: "/",component: Layout,redirect: "/index",hidden: false,children: [{name: "index",path: "/index",meta: { title: "index" },component: () => import("@/views/index"),},],},{id: 2,name: "/form",path: "/form",component: Layout,redirect: "/form/index",hidden: false,children: [{name: "/form/index",path: "/form/index",meta: { title: "form" },component: () => import("@/views/form"),},],},{id: 3,name: "/example",path: "/example",component: Layout,redirect: "/example/tree",meta: { title: "example" },hidden: false,children: [{name: "/tree",path: "/example/tree",meta: { title: "tree" },component: () => import("@/views/tree"),},{name: "/copy",path: "/example/copy",meta: { title: "copy" },component: () => import("@/views/tree/copy"),},],},{id: 4,name: "/table",path: "/table",component: Layout,redirect: "/table/index",hidden: false,meta: { roles: ["admin"] },children: [{name: "/table/index",path: "/table/index",meta: { title: "table", roles: ["admin"] },component: () => import("@/views/table"),},],},{id: 5,name: "/admin",path: "/admin",component: Layout,redirect: "/admin/index",hidden: false,meta: { roles: ["admin"] },children: [{name: "/admin/index",path: "/admin/index",meta: { title: "admin", roles: ["admin"] },component: () => import("@/views/admin"),},],},{id: 6,name: "/people",path: "/people",component: Layout,redirect: "/people/index",hidden: false,meta: { roles: ["admin", "common_user"] },children: [{name: "/people/index",path: "/people/index",meta: { title: "people", roles: ["admin", "common_user"] },component: () => import("@/views/people"),},],},{id: 7,name: "/404",path: "/404",component: () => import("@/views/404"),},// 注意404页面要放到最后{ path: "*", redirect: "/404", hidden: true },
]const router = new VueRouter({mode: "history",base: process.env.BASE_URL,routes: constantRoutes,
})export default router
这里我们根据 vue-router官方推荐 的方法通过meta标签来标示改页面能访问的权限有哪些。如meta: { role: [‘admin’,‘super_editor’] }表示该页面只有admin和超级编辑才能有资格进入。
注意事项:这里有一个需要非常注意的地方就是 404 页面一定要最后加载,如果放在constantRoutes一同声明了404,后面的所以页面都会被拦截到404
步骤二:登录时获取用户信息,存入vuex中,存储token
login/index.vue
methods: {login () {this.$refs.userForm.validate((valid) => {if (valid) {// 模拟登录接口去请求用户数据setTimeout(() => {// 这里的res就是模拟后台返回的用户数据(不包含用户角色,一般角色是由单独的一个接口返回)const res = dynamicUserData.filter((item) => item.username === this.user.username)[0]console.log(res)// 存储用户的信息及token到vuex,并做sessionStorage持久化处理this.$store.commit('User/saveUserInfo', res)Message({ type: 'success', message: "登录成功", showClose: true, duration: 3000 })this.$router.push({ path: "/index" })}, 1000)} else return false})}}
附:vuex持久化处理
import Vue from 'vue'
import Vuex from 'vuex'
import User from './modules/user'
import permission from './modules/permission'
import createPersistedState from 'vuex-persistedstate'
Vue.use(Vuex)export default new Vuex.Store({state: {},mutations: {},actions: {},modules: {User,permission,},plugins: [createPersistedState({storage: window.sessionStorage, // 可选sessionStorage localStoragereducer(val) {return {User: val.User,}},}),],
})
步骤【三四】:在路由拦截器中,通过token去获取用户角色,拿角色去获取所有可访问的路由,调用router.addrouters(store.state.addRouters)添加可访问的路由
路由钩子逻辑:
是否为白名单页面是: 直接进入不是: 判断是否有token无token:跳转到login登录页有token: 判断用户是否有角色权限表有权限表:直接进入无权限表:调接口获取用户角色,并存储到vuex根据返回的角色和路由表每个页面的需要的权限对比,生成可访问的路由表使用router.addRouters()添加路由
路由导航守卫:
import router from "./index"
import NProgress from "nprogress" // progress bar
import store from "@/store"
import menu from "@/mock/menu.js"NProgress.configure({ showSpinner: false }) // NProgress Configuration// 白名单页面直接进入
const whiteList = ["/login"]router.beforeEach((to, from, next) => {NProgress.start()// 白名单页面,不管是否有token,是否登录都直接进入if (whiteList.indexOf(to.path) !== -1) {next()return false}// 有token(代表了有用户信息,但是不确定有没有角色权限数组)if (store.state.User.token) {// 判断当前用户是否有角色权限数组, 是登录状态则一定有路由,直接放行,不是登录状态则去获取路由菜单登录// 刷新时hasRoles会重置为false,重新去获取 用户的角色列表const hasRoles = store.state.permission.roles && store.state.permission.roles.length > 0if (!hasRoles) {setTimeout(async () => {const roles = menu.filter((item) => item.token === store.state.User.token)[0].roles// 将该角色权限数组存储到vuex中store.commit("permission/setRoles", roles)// 根据返回的角色信息去过滤异步路由中该角色可访问的页面const accessRoutes = await store.dispatch("permission/generateRoutes", roles)// dynamically add accessible routesrouter.addRoutes(accessRoutes)// hack方法 router.addRoutes之后的next()可能会失效,因为可能next()的时候路由并没有完全add完成 next(to)解决next({ ...to, replace: true })}, 500)} else {next() //当有用户权限的时候,说明所有可访问路由已生成 如访问没权限的全面会自动进入404页面}} else {next({ path: "/login" })}
})router.afterEach(() => {// finish progress barNProgress.done()
})
vuex中做的事为: 将定义好的动态路由 通过 角色权限数组(后台返回的)进行过滤,过滤出用户有的路由,然后将该过滤后的路由添加到静态路由后面去
store/permission.js
import { asyncRoutes, constantRoutes } from '@/router'
/*** Filter asynchronous routing tables by recursion* @param routes asyncRoutes* @param roles*/
export function filterAsyncRoutes(routes, roles) {const res = []routes.forEach(route => {const tmp = { ...route }if (hasPermission(roles, tmp)) {if (tmp.children) {tmp.children = filterAsyncRoutes(tmp.children, roles)}res.push(tmp)}})return res
}function hasPermission(roles, route) {console.log(roles)console.log(route)if (route.meta && route.meta.roles) {console.log(roles.some(role => route.meta.roles.includes(role)))return roles.some(role => route.meta.roles.includes(role))} else {return true}
}const state = {roles: [],routes: [],addRoutes: [],
}
const mutations = {setRoles(state, val) {state.roles = val},SET_ROUTES: (state, routes) => {state.addRoutes = routesstate.routes = constantRoutes.concat(routes)},
}
const actions = {generateRoutes({ commit }, roles) {return new Promise(resolve => {let accessedRoutesif (roles.includes('admin')) { // admin直接添加所有权限accessedRoutes = asyncRoutes || []} else {accessedRoutes = filterAsyncRoutes(asyncRoutes, roles)}commit('SET_ROUTES', accessedRoutes)resolve(accessedRoutes)})},
}
export default {namespaced: true,state,mutations,actions,
}
步骤四:退出时清空用户信息,清空角色,清空路由
methods: {// 退出登录handleLogout() {window.localStorage.removeItem("token")// 清除用户信息this.$store.commit("User/removeUserInfo")// 清除角色权限列表this.$store.commit("permission/setRoles", [])// 清除角色权限数组this.$store.commit("permission/SET_ROUTES", [])Message({type: "success",message: "退出登录",showClose: true,duration: 3000,})this.$router.push({ path: "/login" })},}
希望能帮到你
文章参考:
花裤衩大佬:花裤衩大佬
本文代码:github 求 star
相关文章:
前端实现动态路由(前端控制全部路由,后端返回用户角色)
优缺点 优点: 不用后端帮助,路由表维护在前端逻辑相对比较简单,比较容易上手权限少的系统用前端鉴权更加方便 缺点: 线上版本每次修改权限页面,都需要重新打包项目大型项目不适用如果需要在页面中增加角色并且控制可以访问的页…...
Spring5学习笔记—Spring事务处理
✅作者简介:大家好,我是Leo,热爱Java后端开发者,一个想要与大家共同进步的男人😉😉 🍎个人主页:Leo的博客 💞当前专栏: Spring专栏 ✨特色专栏: M…...
如何增长LLM推理token,从直觉到数学
背景: 最近大模型输入上文长度增长技术点的研究很火。为何要增长token长度,为何大家如此热衷于增长输入token的长度呢?其实你如果是大模型比价频繁的使用者,这个问题应该不难回答。增长了输入token的长度,那需要多次出入才能得到…...
《穷爸爸与富爸爸》时间是最宝贵的资产,只有它对所有人都是公平的
《穷爸爸与富爸爸》时间是最宝贵的资产,只有它对所有人都是公平的 罗伯特清崎,日裔美国人,投资家、教育家、企业家。 萧明 译 文章目录 《穷爸爸与富爸爸》时间是最宝贵的资产,只有它对所有人都是公平的[toc]摘录各阶层现金流图支…...
Git结合Gitee的企业开发模拟
本系列有两篇文章: 一是另外一篇《快速使用Git完整开发》,主要说明了关于Git工具的基础使用,包含三板斧(git add、git commit、git push)、Git基本配置、版本回退、分支管理、公钥与私钥、远端仓库和远端分支、忽略文…...
WEBGL(2):绘制单个点
代码如下: <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><meta http-equiv"X-UA-Compatible" content"IEedge"><meta name"viewport" content"widthdevi…...
C# task多线程创建,暂停,继续,结束使用
1、多线程任务创建 private void button1_Click(object sender, EventArgs e) //创建线程{CancellationToken cancellationToken tokensource.Token;Task.Run(() > //模拟耗时任务{for (int i 0; i < 100; i){if (cancellationToken.IsCancellationRequested){return;…...
界面控件DevExpress WinForms(v23.2)下半年发展路线图
本文主要概述了官方在下半年(v23.2)中一些与DevExpress WinForms相关的开发计划,重点关注的领域将是可访问性支持和支持.NET 8。 DevExpress WinForms有180组件和UI库,能为Windows Forms平台创建具有影响力的业务解决方案。同时能…...
vue实现按需加载的多种方式
1.import动态导入 const Home () > import( /* webpackChunkName: "Home" */ /views/Home.vue); 2.使用vue异步组件resolve 这种方式没有成功 //const 组件名 resolve > require([‘组件路径’],resolve) //(这种情况下一个组件生成一个js文件…...
el-switch组件在分页情况下的使用
1.需求: 系统使用者在点击发布状态的开关后,可以对应的发布或者取消发布试卷 2.前端代码: html代码(这里不贴其他表单项的代码了,直接贴el-Switch组件的代码): <!-- qwy: 使用Switch组件,设置发布状态,业务逻辑:在页面初始渲染的时候应该查询发布状态,以根据状…...
【100天精通python】Day49:python web编程_web框架,Flask的使用
目录 1 Web 框架 2 python 中常用的web框架 3 Flask 框架的使用 3.1 Flask框架安装 3.2 第一个Flask程序 3.3 路由 3.3.1 基本路由 3.3.2 动态路由 3.3.3 HTTP 方法 3.3.4 多个路由绑定到一个视图函数 3.3.5 访问URL 参数的路由 3.3.6 带默认值的动态路由 3.3.7 带…...
sql 查重以及删除重复
查重 select count(1),content from t_mall_longping group by content having count(1)>1 稳重删除重复(技术来源于 百度文心一言,好屌呀) CREATE TABLE tmp_duplicates ( hxid INT PRIMARY KEY );INSERT INTO tmp_duplicates SEL…...
Flux语言 -- InfluxDB笔记二
1. 基础概念理解 1.1 语序和MySQL不一样,像净水一样通过管道一层层过滤 1.2 不同版本FluxDB的语法也不太一样 2. 基本表达式 import "array" s 10 * 3 // 浮点型只能与浮点型进行运算 s1 9.0 / 3.0 s2 10.0 % 3.0 // 等于 1 s3 10.0 ^ 3.0 // 等于…...
18.Oauth2-微服务认证
1.Oauth2 OAuth 2.0授权框架支持第三方支持访问有限的HTTP服务,通过在资源所有者和HTTP服务之间进行一个批准交互来代表资源者去访问这些资源,或者通过允许第三方应用程序以自己的名义获取访问权限。 为了方便理解,可以想象OAuth2.0就是在用…...
vue和node使用websocket实现数据推送,实时聊天
需求:node做后端根据websocket,连接数据库,数据库的字段改变后,前端不用刷新页面也能更新到数据,前端也可以发送消息给后端,后端接受后把前端消息做处理再推送给前端展示 1.初始化node,生成pac…...
汽车电子笔记之:基于AUTOSAR的多核监控机制
目录 1、概述 2、系统监控的目标 2.1、任务的状态机 2.2、任务服务函数 2.3、任务周期性事件 2.4、时间监控的指标 2.5、时间监控的原理 2.6、CPU负载率监控原理 2.6.1、设计思路 2.6.2、监控方法的评价 3、基于WDGM模块热舞时序监控方法 3.1、活跃监督 3.2、截至时…...
GDB 源码分析 -- 断点源码解析
文章目录 一、断点简介1.1 硬件断点1.2 软件断点 二、断点源码分析2.1 断点相关结构体2.1.1 struct breakpoint2.1.2 struct bp_location 2.2 断点源码简介2.3 break设置断点2.4 enable break2.5 disable breakpoint2.6 delete breakpoint2.7 info break 命令源码解析 三、Linu…...
SpringMVC概述与简单使用
1.SpringMVC简介 SpringMVC也叫做Spring web mvc,是 Spring 框架的一部分,是在 Spring3.0 后发布的。 2.SpringMVC优点 1.基于 MVC 架构 基于 MVC 架构,功能分工明确。解耦合, 2.容易理解,上手快;使用简单。 就可以…...
传输层—UDP原理详解
目录 前言 1.netstat 2.pidof 3.UDP协议格式 4.UDP的特点 5.面向数据报 6.UDP的缓冲区 7.UDP使用注意事项 8.基于UDP的应用层协议 总结 前言 在之前的文章中为大家介绍了关于网络协议栈第一层就是应用层,包含套接字的使用,在应用层编码实现服务…...
CK-GW06-E03与汇川PLC的EtherNet/IP通信
准备阶段: CK-GWO6-E03网关POE交换机网线汇川PLC编程软件汇川AC801-0221-U0R0型号PLC 1.打开汇川PLC编程软件lnoProShop(V1.6.2)SP2 新建工程,选择对应的PLC型号,编程语言选择为“结构化文本(ST)语言”,然…...
未发表】“VMD-BKA-CNN-BiLSTM四模型多变量时序预测一键对比Matlab代码
【未发表】VMD-BKA-CNN-BiLSTM四模型多变量时序预测一键对比 Matlab代码 可用于风电预测,光伏预测等 基于变分模态分解结合黑翅鸳算法优化卷积神经网络结合双向长短期记忆神经网络的数据多变量时序预测一键对比 各种对比图都有 包含VMD-BKA-CNN-BiLSTM,VMD-CNN…...
终极指南:Hilt依赖注入在Droid-ify开源应用中的实战应用 [特殊字符]
终极指南:Hilt依赖注入在Droid-ify开源应用中的实战应用 🚀 【免费下载链接】client F-Droid client with Material UI. 项目地址: https://gitcode.com/gh_mirrors/clie/client 在Android应用开发领域,Droid-ify作为一个优秀的F-Dro…...
Legacy-iOS-Kit系统降级全指南:让老旧iOS设备重获新生
Legacy-iOS-Kit系统降级全指南:让老旧iOS设备重获新生 【免费下载链接】Legacy-iOS-Kit An all-in-one tool to downgrade/restore, save SHSH blobs, and jailbreak legacy iOS devices 项目地址: https://gitcode.com/gh_mirrors/le/Legacy-iOS-Kit 一、问…...
CanCanCan控制器助手终极指南:load_and_authorize_resource深度解析与最佳实践
CanCanCan控制器助手终极指南:load_and_authorize_resource深度解析与最佳实践 【免费下载链接】cancancan The authorization Gem for Ruby on Rails. 项目地址: https://gitcode.com/gh_mirrors/ca/cancancan CanCanCan是Ruby on Rails最强大的授权gem&…...
CGAL Point_set_processing 点集处理函数自查表
参考来源: CGAL 6.1.1 - Point Set Processing: Algorithms 一、尺度 / K 值估算 返回值函数名作用用法示例size_testimate_global_k_neighbor_scale估算全局最优 K 邻域estimate_global_k_neighbor_scale(points)FTestimate_global_range_scale估算全局最优搜索…...
构建专属数字分身:Duix-Avatar本地化部署与应用全指南
构建专属数字分身:Duix-Avatar本地化部署与应用全指南 【免费下载链接】Duix-Avatar 项目地址: https://gitcode.com/GitHub_Trending/he/Duix-Avatar 在数字化时代,拥有一个能够自主生成视频内容的AI助手已成为提升创作效率的关键。Duix-Avatar…...
Alt App Installer革新:突破微软商店限制的Windows应用安装解决方案
Alt App Installer革新:突破微软商店限制的Windows应用安装解决方案 【免费下载链接】alt-app-installer A Program To Download And Install Microsoft Store Apps Without Store 项目地址: https://gitcode.com/gh_mirrors/alt/alt-app-installer 微软商店…...
从潍坊一中赛题看算法竞赛中的数据类型陷阱与优化策略
1. 数据类型陷阱:从潍坊一中T1赛题看数值溢出问题 第一次参加算法竞赛的同学,90%都会在数据类型上栽跟头。就拿潍坊一中T1"揽月湖"这道题来说,表面是简单的数学表达式计算,实则是数据类型选择的经典案例。题目要求计算3…...
卡证检测矫正模型开发环境搭建:PyCharm/IDEA项目配置全攻略
卡证检测矫正模型开发环境搭建:PyCharm/IDEA项目配置全攻略 你是不是刚拿到一个卡证检测矫正模型的项目,看着一堆代码和配置文件有点无从下手?特别是想用PyCharm或者IDEA这样的专业工具来开发调试,却不知道从哪一步开始配置环境&…...
NSudo终极指南:3大核心功能解锁Windows系统权限管理新境界
NSudo终极指南:3大核心功能解锁Windows系统权限管理新境界 【免费下载链接】NSudo [Deprecated, work in progress alternative: https://github.com/M2Team/NanaRun] Series of System Administration Tools 项目地址: https://gitcode.com/gh_mirrors/ns/NSudo …...
