前端实现动态路由(后端返回权限路由)

在这里插入图片描述

实现思路

1、前端定义静态路由(login登录页这种不需要权限的默认路由)
2、用户登陆时调接口获取用户信息,然后登录到首页
3、前后端定义好路由返回的格式
4、在路由导航钩子beforeEach中去调接口获取动态路由,递归处理该数据为前端可用的路由数据,使用router.addRouters()添加路由

步骤一:前端定义静态路由(login登录页这种不需要权限的默认路由)

router/index.js

import Vue from 'vue'
import VueRouter from 'vue-router'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)
}// 定义好静态路由
const routes = [{path: '/login',name: 'login',component: () => import('../views/login'),hidden: true,},
]const router = new VueRouter({mode: 'history',base: process.env.BASE_URL,routes,
})export default router

步骤二:用户登陆时调接口获取用户信息,然后登录到首页

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持久化处理:使用vuex-persistedstate插件将User仓库的内容存储到sessionStorage中

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,}},}),],
})

步骤三:前后端定义好路由返回的格式

// 后台返回的数据结构
const dynamicUser = [{name: '管理员',avatar: 'https://sf3-ttcdn-tos.pstatp.com/img/user-avatar/ccb565eca95535ab2caac9f6129b8b7a~300x300.image',desc: '管理员 - admin',username: 'admin',password: '654321',token: 'rtVrM4PhiFK8PNopqWuSjsc1n02oKc3f',routes: [{id: 1,name: '/',path: '/',component: 'Layout',redirect: '/index',hidden: false,children: [{ name: 'index', path: '/index', meta: { title: 'index' }, component: 'index/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: 'form/index' }],},{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: 'tree/index' },{ name: '/copy', path: '/example/copy', meta: { title: 'copy' }, component: 'tree/copy' },],},{id: 4,name: '/table',path: '/table',component: 'Layout',redirect: '/table/index',hidden: false,children: [{ name: '/table/index', path: '/table/index', meta: { title: 'table' }, component: 'table/index' }],},{id: 5,name: '/admin',path: '/admin',component: 'Layout',redirect: '/admin/index',hidden: false,children: [{ name: '/admin/index', path: '/admin/index', meta: { title: 'admin' }, component: 'admin/index' }],},{id: 6,name: '/people',path: '/people',component: 'Layout',redirect: '/people/index',hidden: false,children: [{ name: '/people/index', path: '/people/index', meta: { title: 'people' }, component: 'people/index' }],},],},{name: '普通用户',avatar: 'https://sf1-ttcdn-tos.pstatp.com/img/user-avatar/6364348965908f03e6a2dd188816e927~300x300.image',desc: '普通用户 - people',username: 'people',password: '123456',token: '4es8eyDwznXrCX3b3439EmTFnIkrBYWh',routes: [{id: 1,name: '/',path: '/',component: 'Layout',redirect: '/index',hidden: false,children: [{ name: 'index', path: '/index', meta: { title: 'index' }, component: 'index/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: 'form/index' }],},{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: 'tree/index' },{ name: '/copy', path: '/example/copy', meta: { title: 'copy' }, component: 'tree/copy' },],},{id: 4,name: '/table',path: '/table',component: 'Layout',redirect: '/table/index',hidden: false,children: [{ name: '/table/index', path: '/table/index', meta: { title: 'table' }, component: 'table/index' }],},{id: 6,name: '/people',path: '/people',component: 'Layout',redirect: '/people/index',hidden: false,children: [{ name: '/people/index', path: '/people/index', meta: { title: 'people' }, component: 'people/index' }],},],},
]export default dynamicUser

步骤四:路由导航钩子beforeEach处理

路由钩子逻辑:

是否为白名单:是:  直接进入不是:判断是否有token无token:跳转到login登录页有token:判断用户路由状态(是否有路由)有路由: 直接进入无路由: 调接口获取动态路由递归处理返回的路由将递归处理好的路由存储到vuex,设置用户路由状态为true使用router.addRouters()添加路由

路由导航守卫:

import router from './index'
import Layout from '../layout/index'
import NProgress from 'nprogress' // progress bar
import store from '@/store'
import menu from '@/mock/menu.js'// 路由拼接
function loadView(view) {return () => import(`@/views/${view}`)
}
// 路由过滤   遍历路由 转换为组件对象和路径
function filterASyncRoutes(data) {// console.log(data)const routes = data.filter(item => {if (item['component'] === 'Layout') {item.component = Layout} else {item['component'] = loadView(item['component'])}// 路由递归,转换组件对象和路径if (item['children'] && item['children'].length > 0) {item['children'] = filterASyncRoutes(item.children)}return true})// 排序routes.sort((a, b) => a['id'] - b['id'])return routes
}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) {// 判断当前用户是否是登录状态, 是登录状态则一定有路由,直接放行,不是登录状态则去获取路由菜单登录// 刷新时store.state.routerList.hasRoutes会重置为false,重新去获取 异步路由if (!store.state.routerList.hasRoutes) {setTimeout(() => {const res = menu.filter(item => item.token === store.state.User.token)[0].routesconst asyncRouter = filterASyncRoutes(res) // 递归处理后台返回的路由store.commit('routerList/setRouterList', asyncRouter) // 存储到异步的路由到vuexstore.commit('routerList/setHasRoutes', true) // 设置登录状态为truerouter.addRoutes(asyncRouter) // 动态添加可访问路由表next({ ...to, replace: true }) // hack方法 router.addRoutes之后的next()可能会失效,可能next()的时候路由并没有完全add完成 通过next(to)解决}, 500)} else {next() //当有用户权限的时候,说明所有可访问路由已生成 如访问没权限的全面会自动进入404页面}}else {next({path:'/login'})}
})router.afterEach(() => {// finish progress barNProgress.done()
})

注意
这里将异步路由和路由状态的数据放到了routerList.js里面,但是这里是没做缓存的
原因:让用户刷新时这里的数据重置,然后重新走路由钩子的时候就会去调接口获取路由信息。
(为什么不把路由放到sessionStorage中? 原因是路由数组中的component无法保存到sessionStorage中,() => import(@/views/${userAuth.component}) 这种保存不到sessionStorage中 )

获取的用户信息需要存储在vuex并做持久化处理,但是获取的菜单存在vuex中不做持久化处理,让用户在刷新时会清空,重新走获取菜单的接口,也就是下面这段代码

if (!store.state.routerList.hasRoutes) {setTimeout(() => {const res = menu.filter(item => item.token === store.state.User.token)[0].routesconst asyncRouter = filterASyncRoutes(res) // 递归处理后台返回的路由store.commit('routerList/setRouterList', asyncRouter) // 存储到异步的路由到vuexstore.commit('routerList/setHasRoutes', true) // 设置登录状态为truerouter.addRoutes(asyncRouter) // 动态添加可访问路由表next({ ...to, replace: true }) // hack方法 router.addRoutes之后的next()可能会失效,可能next()的时候路由并没有完全add完成 通过next(to)解决}, 500)
}

我公司目前就是采用后端返回路由做的权限管理

希望能帮到你哦

参考代码在github 给我来个star

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

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

相关文章

QT中闹钟的设置

.h文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QPushButton> //按钮 #include <QTextEdit> //文本 #include <QLabel> //标签 #include <QLineEdit> //行编辑器#include <QTimerEvent> //定时器事件类头文件 #…

基于ssm+vue舞蹈网站的设计与实现

基于ssmvue舞蹈网站的设计与实现111 开发工具&#xff1a;idea 数据库mysql5.7 数据库链接工具&#xff1a;navcat,小海豚等 技术&#xff1a;ssm 摘 要 随着科学技术的飞速发展&#xff0c;社会的方方面面、各行各业都在努力与现代的先进技术接轨&#xff0c;通过科技…

介绍几个搜索引擎

Google&#xff1a;全球最大的搜索引擎&#xff0c;提供全面的搜索服务&#xff0c;包括网页、图片、视频、新闻、地图等。 Baidu&#xff1a;中国最大的搜索引擎&#xff0c;提供类似于Google的全面搜索服务&#xff0c;同时也有网盘、知道等功能。 Bing&#xff1a;微软公司…

数学建模--G(1,1)型的灰色预测模型的Python实现

目录 1.算法适用情况 2.算法推演步骤 3.算法核心代码 4.算法效果展示 1.算法适用情况 #1.灰色预测模型简介 """ 1.灰色预测是对既含有已知信息又含有不确定信息的系统进行预测&#xff0c;就是对在一定范围内变化的、与时间有关的灰色过程进行预测。 2.灰色预测…

python 之import与from import 导入库的解析与差异

文章目录 1. **使用import导入整个模块**&#xff1a;2. **使用from import导入特定内容**&#xff1a;注意事项别名的使用 在Python中&#xff0c;import和from import是用于导入模块中内容的两种不同方式。下面详细介绍它们的用法和差异&#xff1a; 1. 使用import导入整个模…

java基础-----第九篇

系列文章目录 文章目录 系列文章目录前言一、GC如何判断对象可以被回收前言 一、GC如何判断对象可以被回收 引用计数法:每个对象有一个引用计数属性,新增一个引用时计数加1,引用释放时计数减1,计 数为0时可以回收, 可达性分析法:从 GC Roots 开始向下搜索,搜索所走过的…

htmx-使HTML更强大

‍本文作者是360奇舞团开发工程师 htmx 让我们先来看一段俳句: javascript fatigue: longing for a hypertext already in hand 这个俳句很有意思&#xff0c;是开源项目htmx文档中写的&#xff0c;意思是说&#xff0c;我们已经有了超文本&#xff0c;为什么还要去使用javascr…

Win7系统电脑开机总出现硬盘自检的简单解决方法

你是不是经常会遇到电脑开机进行硬盘自检&#xff0c;而且每次开机都检查很久不能跳过&#xff1b;怎么才能跳过这一步骤呢&#xff1f;下面教大家如何让Win7系统电脑在开机的时候跳过硬盘自检这一步骤&#xff0c;加快开机时间。 解决步骤&#xff1a; 1、按下“Win R”快捷键…

Java【手撕滑动窗口】LeetCode 438. “字符串中所有异位词“, 图文详解思路分析 + 代码

文章目录 前言一、字符串中所有异位词1, 题目2, 思路分析2.1, 引入哈希表找出异位词2.2, 引入变量记录"有效字符的个数"2.3, left 右移维护窗口2.4, 总结核心步骤 3, 代码 前言 各位读者好, 我是小陈, 这是我的个人主页, 希望我的专栏能够帮助到你: &#x1f4d5; Ja…

弹性盒子的使用

一、定义 弹性盒子是一种用于按照布局元素的一维布局方法&#xff0c;它可以简便、完整、响应式地实现各种页面布局。 容器中存在两条轴&#xff0c;主轴和交叉轴(相当于我们坐标轴的x轴和y轴)。我们可以通过flex-direction来决定主轴的方向。 主轴&#xff08;main axis&am…

运维自动化与Cobbler服务部署

运维自动化与Cobbler服务部署 一.Cobbler简介 1.1.简介 Cobbler是一款Linux生态的自动化运维工具&#xff0c;基于Python2开发&#xff0c;用于自动化批量部署安装操作系 统&#xff1b;其提供基于CLI的管理方式和WEB配置界面&#xff0c;其中WEB配置界面是基于Python2和Djang…

Linux查看是虚拟机还是物理机

第一种方式&#xff1a;dmesg命令 [roottest ~]# dmesg | grep -i hypervisor [ 0.000000] Hypervisor detected: VMware [ 0.001000] TSC freq read from hypervisor : 2903.999 MHz [ 6.311621] [drm] Max dedicated hypervisor surface memory is 0 kiB第二种方式…

K8S Nginx Ingress实现金丝雀发布

通过给 Ingress 资源指定 Nginx Ingress 所支持的 annotation 可实现金丝雀发布。 需给服务创建2个 Ingress&#xff0c;其中1个常规 Ingress&#xff0c;另1个为带 nginx.ingress.kubernetes.io/canary: "true" 固定的 annotation 的 Ingress&#xff0c;称为 Cana…

美团 Flink 资源调度优化实践

摘要&#xff1a;本文整理自美团数据平台计算引擎组工程师冯斐&#xff0c;在 Flink Forward Asia 2022 生产实践专场的分享。本篇内容主要分为四个部分&#xff1a; 相关背景和问题解决思路分析资源调度优化实践后续规划 点击查看原文视频 & 演讲PPT 一、相关背景和问题 在…

【Spring Boot】使用XML配置文件实现数据库操作(一)

使用XML配置文件实现数据库操作&#xff08;一&#xff09; 1.SQL映射文件 SQL映射文件就是我们通常说的mapper.xml配置文件&#xff0c;主要实现SQL语句的配置和映射&#xff0c;同时实现Java的POJO对象与数据库中的表和字段进行映射关联的功能。 1.1 mapper.xml的结构 下…

100天精通Python(可视化篇)——第99天:Pyecharts绘制多种炫酷K线图参数说明+代码实战

文章目录 专栏导读一、K线图介绍1. 说明2. 应用场景 二、配置说明三、K线图实战1. 普通k线图2. 添加辅助线3. k线图鼠标缩放4. 添加数据缩放滑块5. K线周期图表 书籍推荐 专栏导读 &#x1f525;&#x1f525;本文已收录于《100天精通Python从入门到就业》&#xff1a;本专栏专…

Unity中Shader的混合模式Blend

文章目录 前言一、混合的作用就是实现各种半透明效果二、混合操作三、在 Shader 中暴露两个属性 来调节 混合的效果 前言 Unity中Shader的混合模式Blend 一、混合的作用就是实现各种半透明效果 这里用PS里的混合作为例子 没选择混合效果前&#xff0c;显示的效果是这样 选择…

基于 Zookeeper 实现服务注册和服务发现

文章目录 前言声明前置知识服务注册和发现Zookeeper 工作原理实现过程注册中心服务注册服务发现 总结 前言 无论是采用SOA还是微服务架构&#xff0c;都需要使用服务注册和服务发现组件。我刚开始接触 Dubbo 时一直对服务注册/发现以及 Zookeeper 的作用感到困惑&#xff0c;现…

React 18 对 state 进行保留和重置

参考文章 对 state 进行保留和重置 各个组件的 state 是各自独立的。根据组件在 UI 树中的位置&#xff0c;React 可以跟踪哪些 state 属于哪个组件。可以控制在重新渲染过程中何时对 state 进行保留和重置。 UI 树 浏览器使用许多树形结构来为 UI 建立模型。DOM 用于表示 …

解决Linux Ubuntu上安装RabbitMQ服务后的公网远程访问问题,借助cpolar内网穿透技术

文章目录 前言1.安装erlang 语言2.安装rabbitMQ3. 内网穿透3.1 安装cpolar内网穿透(支持一键自动安装脚本)3.2 创建HTTP隧道 4. 公网远程连接5.固定公网TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址 前言 RabbitMQ是一个在 AMQP(高级消息队列协议)基…