当前位置: 首页 > news >正文

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

在这里插入图片描述

优缺点

优点:

  • 不用后端帮助,路由表维护在前端
  • 逻辑相对比较简单,比较容易上手
  • 权限少的系统用前端鉴权更加方便

缺点:

  • 线上版本每次修改权限页面,都需要重新打包项目
  • 大型项目不适用
  • 如果需要在页面中增加角色并且控制可以访问的页面,则不能用前端鉴权

具体思路

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):绘制单个点

代码如下&#xff1a; <!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)下半年发展路线图

本文主要概述了官方在下半年&#xff08;v23.2&#xff09;中一些与DevExpress WinForms相关的开发计划&#xff0c;重点关注的领域将是可访问性支持和支持.NET 8。 DevExpress WinForms有180组件和UI库&#xff0c;能为Windows Forms平台创建具有影响力的业务解决方案。同时能…...

vue实现按需加载的多种方式

1.import动态导入 const Home () > import( /* webpackChunkName: "Home" */ /views/Home.vue); 2.使用vue异步组件resolve 这种方式没有成功 //const 组件名 resolve > require([‘组件路径’],resolve) //&#xff08;这种情况下一个组件生成一个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 稳重删除重复&#xff08;技术来源于 百度文心一言&#xff0c;好屌呀&#xff09; CREATE TABLE tmp_duplicates ( hxid INT PRIMARY KEY );INSERT INTO tmp_duplicates SEL…...

Flux语言 -- InfluxDB笔记二

1. 基础概念理解 1.1 语序和MySQL不一样&#xff0c;像净水一样通过管道一层层过滤 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服务&#xff0c;通过在资源所有者和HTTP服务之间进行一个批准交互来代表资源者去访问这些资源&#xff0c;或者通过允许第三方应用程序以自己的名义获取访问权限。 为了方便理解&#xff0c;可以想象OAuth2.0就是在用…...

vue和node使用websocket实现数据推送,实时聊天

需求&#xff1a;node做后端根据websocket&#xff0c;连接数据库&#xff0c;数据库的字段改变后&#xff0c;前端不用刷新页面也能更新到数据&#xff0c;前端也可以发送消息给后端&#xff0c;后端接受后把前端消息做处理再推送给前端展示 1.初始化node&#xff0c;生成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 框架的一部分&#xff0c;是在 Spring3.0 后发布的。 2.SpringMVC优点 1.基于 MVC 架构 基于 MVC 架构&#xff0c;功能分工明确。解耦合&#xff0c; 2.容易理解&#xff0c;上手快&#xff1b;使用简单。 就可以…...

传输层—UDP原理详解

目录 前言 1.netstat 2.pidof 3.UDP协议格式 4.UDP的特点 5.面向数据报 6.UDP的缓冲区 7.UDP使用注意事项 8.基于UDP的应用层协议 总结 前言 在之前的文章中为大家介绍了关于网络协议栈第一层就是应用层&#xff0c;包含套接字的使用&#xff0c;在应用层编码实现服务…...

CK-GW06-E03与汇川PLC的EtherNet/IP通信

准备阶段&#xff1a; CK-GWO6-E03网关POE交换机网线汇川PLC编程软件汇川AC801-0221-U0R0型号PLC 1.打开汇川PLC编程软件lnoProShop(V1.6.2)SP2 新建工程&#xff0c;选择对应的PLC型号&#xff0c;编程语言选择为“结构化文本&#xff08;ST&#xff09;语言”&#xff0c;然…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

华为OD机试-食堂供餐-二分法

import java.util.Arrays; import java.util.Scanner;public class DemoTest3 {public static void main(String[] args) {Scanner in new Scanner(System.in);// 注意 hasNext 和 hasNextLine 的区别while (in.hasNextLine()) { // 注意 while 处理多个 caseint a in.nextIn…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

学习STC51单片机32(芯片为STC89C52RCRC)OLED显示屏2

每日一言 今天的每一份坚持&#xff0c;都是在为未来积攒底气。 案例&#xff1a;OLED显示一个A 这边观察到一个点&#xff0c;怎么雪花了就是都是乱七八糟的占满了屏幕。。 解释 &#xff1a; 如果代码里信号切换太快&#xff08;比如 SDA 刚变&#xff0c;SCL 立刻变&#…...

ip子接口配置及删除

配置永久生效的子接口&#xff0c;2个IP 都可以登录你这一台服务器。重启不失效。 永久的 [应用] vi /etc/sysconfig/network-scripts/ifcfg-eth0修改文件内内容 TYPE"Ethernet" BOOTPROTO"none" NAME"eth0" DEVICE"eth0" ONBOOT&q…...

【数据分析】R版IntelliGenes用于生物标志物发现的可解释机器学习

禁止商业或二改转载&#xff0c;仅供自学使用&#xff0c;侵权必究&#xff0c;如需截取部分内容请后台联系作者! 文章目录 介绍流程步骤1. 输入数据2. 特征选择3. 模型训练4. I-Genes 评分计算5. 输出结果 IntelliGenesR 安装包1. 特征选择2. 模型训练和评估3. I-Genes 评分计…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好&#xff0c;我是java1234_小锋老师&#xff0c;看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】&#xff0c;分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

C#学习第29天:表达式树(Expression Trees)

目录 什么是表达式树&#xff1f; 核心概念 1.表达式树的构建 2. 表达式树与Lambda表达式 3.解析和访问表达式树 4.动态条件查询 表达式树的优势 1.动态构建查询 2.LINQ 提供程序支持&#xff1a; 3.性能优化 4.元数据处理 5.代码转换和重写 适用场景 代码复杂性…...

Windows安装Miniconda

一、下载 https://www.anaconda.com/download/success 二、安装 三、配置镜像源 Anaconda/Miniconda pip 配置清华镜像源_anaconda配置清华源-CSDN博客 四、常用操作命令 Anaconda/Miniconda 基本操作命令_miniconda创建环境命令-CSDN博客...

NPOI Excel用OLE对象的形式插入文件附件以及插入图片

static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...