从零开始Vue3+Element Plus后台管理系统(18)——权限路由实现

news2024/12/23 9:38:39

一开始打算做两种模式的路由权限,最后还是分成了3种,分别是:

  1. 前端固定路由,所有路由是固定的,通过权限过滤菜单和显示
  2. 前端动态路由,通过权限过滤路由表和菜单
  3. 后端动态路由,获取接口返回数据,挂载路由表和菜单
VITE_PERMISSION_MODE = 'CONSTANT'
# VITE_PERMISSION_MODE = 'FRONT'
# VITE_PERMISSION_MODE = 'BACK'

因为权限配置灵活,实际工作中一般采用第3种。在个人demo或者权限简单的项目中,第一种也够用。

简要流程

下图是一个简单流程说明,主要在路由的全局前置守卫router.beforeEach体现。

image.png

各个模块的路由对应views,分文件放在router/modules,方便后面统一使用
image.png

路由入口文件 router/index.ts

  1. 存放系统固定的几个路由(登录、注册、403、404…)
const constantRoutes: RouteRecordRaw[] = [
  {
    path: '/',
    name: 'Home',
    redirect: '/dashboard',
    hidden: true,
    meta: {
      title: 'home'
    }
  },
  {
    path: '/login',
    name: 'Login',
    hidden: true,
    meta: {
      title: 'signIn'
    },
    component: () => import(/* webpackChunkName: "login" */ '../views/login/login.vue')
  },
  {
    path: '/403',
    name: '403',
    hidden: true,
    meta: {
      title: '没有权限'
    },
    component: () => import(/* webpackChunkName: "400" */ '../views/403.vue')
  }
]
const lastRoutes = [
  {
    path: '/:pathMatch(.*)*',
    name: '404',
    hidden: true,
    meta: {
      title: '404'
    },
    component: () => import(/* webpackChunkName: "400" */ '../views/404.vue')
  }
]
  1. 获取router/modules文件夹中注册个模块路由
const modules = import.meta.glob('./modules/**/*.ts', { eager: true })

let routeModuleList: RouteRecordRaw[] = []

// 获取路由并排序
Object.values(modules).forEach((key: any) => {
  const mod = key.default || []
  const modList = Array.isArray(mod) ? [...mod] : [mod]
  routeModuleList.push(...modList)
})
  1. 导出挂载在app上的router。

前端固定路由模式会在此把所有路由挂载上。动态路由只需要挂载constanctRoutes,动态路由在前置守卫中挂载。

let routes = constantRoutes

// 前端固定路由模式
if (import.meta.env.VITE_PERMISSION_MODE === 'CONSTANT') {
  routes = [...routeModuleList, ...constantRoutes]
}

const router = createRouter({
  history: createWebHashHistory(),
  routes
})

export default router
export { constantRoutes, routeModuleList, lastRoutes }

除了router文件夹中的文件,我们还需要:

  • useUserStore 管理用户状态,判断路由权限时会用到它,侧边栏菜单的路由表也暂时放在这里。
  • 两个API:获取用户信息、获取路由信息

通用判断

当一个导航触发时,我们通过前置守卫来处理各种情况下的导航——判断是否放行,或是跳转其他页面。

代码放在router/permission.ts,如果你习惯放在src下也没问题。

  • 如果用户未登录,
    当前路由在白名单则直接放行,否则跳转到登录页面/login

  • 如果用户已登录,导航到/login,则直接进入系统首页/

// 用户已登录
  if (useUser.userid) {
    if (to.path === '/login') {
      return '/'
    }
    ...
  } else {
    // 白名单,直接放行
    if (whiteList.indexOf(to.path) > -1) return true
    // 非白名单,去登录
    else return '/login'
  }

继续往下走,需要用到开始说的3种路由模式分别处理。

1. 前端固定路由

我们扩展了_RouteRecordBase接口,增加roles用于保存可访问路由的角色

declare module 'vue-router' {
  interface _RouteRecordBase {
    hidden?: boolean
  }

  interface RouteMeta {
    order?: number
    roles?: array
  }
}

router/modules/system.ts

    ...
    {
        path: 'account',
        name: 'account',
        meta: {
          title: 'accountManagement',
          roles: [RoleEnum.USER]   // 用于判断角色权限
        },
        component: () => import('~/views/system/account/index.vue')
    },
    ...

在登录状态下,只需要判断用户角色是否能够访问这个路由即可,如果没有权限则跳转去403页面

// 前端固定路由模式,如果没有权限,进入403页面
    if (
      import.meta.env.VITE_PERMISSIOIN_MODE === 'CONSTANT' &&
      to.meta.roles &&
      !to.meta.roles.includes(role)
    ) {
      return '/403'
    }

前端动态路由模式

无论是前端还是后端动态路由模式,都需要动态挂载。

    // 前端固定路由模式,如果没有权限,进入403页面
    if (
      ...
    }
    // 前端动态路由和后端动态路由,动态挂载路由
    else {
      if (!to.redirectedFrom) {
        await addAsyncRoutes(router, useUser)

        return { ...to, replace: true }
      } else return true
    }

前端模式中,通过路由角色权限和当前用户角色比对,筛选出有权限的路由,挂载到router上

后端模式中,通过接口返回数据,组装成前端可用的路由数据,挂载到router上

动态挂载路由: router.addRoute(route)

在此,因为addRoute不会改变router.optioins.routes(创建路由器时的原始routes),所以挂载后的路由数据,我们需要保存起来,以便侧边栏菜单使用。

async function addAsyncRoutes(router, userStore) {
  const permissionMode = import.meta.env.VITE_PERMISSIOIN_MODE

  let filteredRoutes = <RouteRecordRaw[]>[]
  // 前端动态路由模式
  if (permissionMode === 'FRONT') {
    filteredRoutes = filterFunc(routeModuleList)
  }
  // 后端动态路由模式
  if (permissionMode === 'BACK') {
    let routes = await getBackAsyncRoutes(userStore.userid)
    filteredRoutes = formatAsyncRoutes(routes)
  }
  console.log(filteredRoutes)
  filteredRoutes.forEach((val) => router.addRoute(val))
  userStore.setAsyncRoutes(filteredRoutes) // 保存最新的路由信息
}

所以前端动态路由,只需过滤出如何角色权限的路由即可,在router/index导出的模块路由数据中比对role即可。

后端动态路由

它和前端模式的区别就是,路由数据通过接口获取,拿到数据后,最重要的操作就是重新拼装成前端可用的形式。

async function getBackAsyncRoutes(userid: number) {
  return await systemApi.getRoutes({ userid })
}

const modules = import.meta.glob('~/views/**/**.vue')

// 把接口路由组装成前端可用结构
function formatAsyncRoutes(routes: any[]) {
  routes.forEach((r) => {
    if (r.component === 'layout' || !r.component) {
      r.component = Layout
    } else {
      r.component = modules[`/src/views${r.component}`]
    }
    if (r.children && r.children.length > 0) {
      r.children = formatAsyncRoutes(r.children)
    }
  })
  return routes
}

产品需求千千万,万变不离其宗 😄

写在最后

路由权限这块,这也是项目最初立下的Flag,在我✍️写到系统第18篇文章的时候终于写了,刚开始的时候还是碰到一些问题,但是当我细细梳理,画出思维导图,写完文章后,觉得一切都清晰起来。

如果一味前行不作停留,不去回顾和总结,很多东西带着一知半解就过去了忘记了。

在忙碌的项目中,我觉得自己变成了一个螺丝钉,没有丝毫成长。停下来做一些输出和总结,整装待发反而更好。

项目地址

本项目GIT地址:https://github.com/lucidity99/mocha-vue3-system

如果有帮助,给个star ✨ 点个赞👍

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

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

相关文章

什么工程项目管理软件好用?

工程项目比较多&#xff0c;经常忘记项目的进度&#xff0c;想要可以查看项目进展的项目管理软件&#xff1f; 大多数时候&#xff0c;面对项目进度没有头绪&#xff0c;看不懂&#xff0c;无法把握&#xff1b;根本原因不在于题主所说的&#xff0c;是否缺少一张合适的项目进…

你必须知道的常用的足够简练的Python代码

许多程序员喜欢Python&#xff0c;因为它的语法简单简洁。下面提供的这些 Python 代码足够简练&#xff0c;可用于解决常见问题。 1.提取字典的键值对 dict1 {A:33, B:43, C:88, D:56} # 提取字典中值大于50的键值对 dict2 { key:value for key, value in dict1.items() if …

curl 命令-接口测试

curl 命令-接口测试 JUST DO IT 温暖春日 在linux/Unix 为代表的os上, 对后端进行测试, 模拟连接请求都会书写脚本 场景: 在Linux 上接口测试工具有ab, restClient, postman等, 最常用的方法是curl进行简单测试 curl是非常方便的Rest 客户端, 可以很方便的完成 Rest API测…

Hadoop教程第一章之Hadoop简介

1. Hadoop是什么 Hadoop是一个由Apache基金会所开发的分布式系统基础架构。主要解决&#xff0c;海量数据的存储和海量数据的分析计算问题。广义上来说&#xff0c;Hadoop通常是指一个更广泛的概念——Hadoop生态圈。 2. Hadoop的三大发行版本 Apache版本最原始&#xff08…

Python读取SD卡二进制数据

在我们使用 STM32 或者 FPGA 采集数据的时候&#xff0c;需要将数据存储到SD卡中&#xff0c;因为数据是按照地址存储的&#xff0c;并且没有文件结构&#xff0c;所以不能直接用电脑的文件管理器读取&#xff0c;下面是一种读取数据的办法 实验平台 正点原子STM32F407ZG探索…

现代化智能十防一体化智慧档案馆平台所具备的必要功能

现代化智能档案室的建设以物联网技术为支撑&#xff0c;包括智能密集架、恒温恒湿消毒净化设备、温湿度传感器、空气质量传感器、空气净化消毒设备、红外防盗设备、门禁设备、防火设备、漏水设备、预警设备、视频监控设备等&#xff0c;集中为一体的管理平台为智能档案室集成平…

金融行业机房监控4大难题?你中招了吗

信息化时代的今天&#xff0c;信息成为我们生活和工作中不可缺少的一部分&#xff0c;由金融行业系统承担&#xff0c;每天有大量的数据交换。 因此&#xff0c;近年来&#xff0c;银行系统对其机房的要求也越来越严格&#xff0c;同时也越来越向智能化、集约化方向发展。 金融…

opencv c++小笔记本(三)

opencv 一图像通道的分离和合并二.图像色彩改变三.简单形状识别1.灰度处理2.高斯滤波3.边缘检测4.膨胀 三.像素点统计四.多边形的绘制和填充五.鼠标操作与响应&#xff08;截图&#xff09;六.图像的像素转换和归一化七.视频文件摄像头使用八.视频的处理与保存九.图像直方图十.…

ESP32-C2开发板 Homekit程序示例

准备 1.1硬件ESP32 C2开发板&#xff0c;如图1-1所示 图1-1 ESP32 C2开发板 1.2软件 CozyLife APP可以在各大应用市场搜索下载&#xff0c;也可以扫描二维码下载如图1-2所示 HomeKit flash download tool 烧录工具 esp32c2 homkit演示固件 烧录教程 打开flash_download_to…

实用工具篇(一):JApiDocs

JApiDocs是一个无需额外注解、开箱即用的SpringBoot接口文档生成工具。 编写和维护API文档这个事情&#xff0c;对于后端程序员来说&#xff0c;是一件恼人但又不得不做的事情&#xff0c;我们都不喜欢写文档&#xff0c;但除非项目前后端代码都是自己写的&#xff0c;否则API…

redis哨兵模式原理

概述 为了实现redis集群的高可用&#xff0c;redis经历了好几次迭代&#xff0c;从最开始的主从模式&#xff0c;到哨兵模式&#xff0c;再到现在的集群模式&#xff0c;可以说架构的优化越来越好&#xff0c;那本篇文章就介绍一下redis的哨兵模式&#xff0c;不过我司其实使用…

阿里云服务器部署flask简单方法

记录如何在阿里云服务器上部署flask接口并实现公网访问。 文章目录 1. 简介2. 部署python3环境3. 生成requirement.txt4. 将项目打包上传5. 安装依赖库6. 查看防火墙7. 测试能否公网访问 1. 简介 因落地通话callback服务测试&#xff0c;需要我写一个测试demo&#xff0c;用于…

Unity Shader中使用GLSL创建材质

目录 Unity Shader格式Properties怎么在脚本中使用类似于glUniform()的功能呢&#xff1f; SubShaderTagsLODpasspass内的tags说明pass内的代码段&#xff08;GLSL&#xff09;GLSL与CG语言的差异1. GLSL不可在外部定义结构体2. 在UnityShader中Uniform可以写在vert frag外面 S…

如何处理图片排重(精准排重,相似排重)

图片相似度对比 1、需求 假如有一个图片池&#xff0c;存有1亿图片。给一张目标图片&#xff0c;在图片池中做匹配。 判断一张图片是否在图片池中出现过。&#xff08;完全一样&#xff09;判断有没有相似的出现过。比如两张图相似度90&#xff0c;两张图片是在描述一件事情。 …

请推荐几个github上的vue的pc端项目?

前言 这是github上一些高收藏的vue PC端的项目&#xff0c;花了一点时间做了一下vue2和vue3的资源分类整理&#xff0c;可以根据自己的学习进度以及需求来选择对应的项目来研究&#xff0c;希望对你有帮助~ Vue2 PC项目 1、 Elemen Star&#xff1a;53.4k 是一个基于Vue.js…

【Unity Optimize】使用图集(Sprite Atlas)优化项目

目录 1 图集&#xff08;Sprite Atlas&#xff09;介绍2 创建与配置Sprite Atlas2.1 创建Sprite Atlas2.1.1 Unity2D项目2.1.2 Unity3D项目 2.2 配置Sprite Atlas2.3 注意事项 3 Sprite Atlas的接口4 Sprite Atlas的优化建议 1 图集&#xff08;Sprite Atlas&#xff09;介绍 …

vue3+element plus+vite 引入本地静态资源图片require报错的原因和解决方案,以及如何在表格中展示图片

文章目录 一、vue3element plusvite 引入本地静态资源图片require报错的原因和解决方案二、vue 3element plusvite 项目中&#xff0c;在el-table中展示本地静态图片总结 一、vue3element plusvite 引入本地静态资源图片require报错的原因和解决方案 在写vue3vite项目的过程中…

Java-代码连接数据库生成POJO、Mapper

本文主要介绍如何在IDEA中&#xff0c;编写代码连接数据库生成对应的POJO、Mapper、Service、Controller 文章目录 前言环境搭建代码开发基本配置常量信息代码生成 测试结果 前言 在实际开发中&#xff0c;设计完数据库后&#xff0c;不可避免需要创建数据库表对应的POJO&…

rt-thread汇总

finish和msh的区别&#xff1f; 这个问题我一直没搞懂&#xff0c;可能得看一下源码才能搞清楚了吧 通过Qemu运行RT-Thread 在windows上通过QEMU快速上手RT-thread smart RT-thread启动流程 rt-thread启动流程 Kconfig语法 Kconfig语法 LOG输出 rt_kprintf("Hello …

InsCode AI ,你的良师益友!

Chat-GTP的火爆程度相信大家已经听说了&#xff0c;也对它有一个基本的初识&#xff0c;它是Open AI所研发的&#xff0c;读者当中应该有不少人已经接触和体验人工智能聊天&#xff0c;以及使用它交流很多问题有关于生活&#xff0c;学习等&#xff0c;而 InsCode AI 也一样能够…