vue3 根据用户权限控制左侧菜单和路由拦截

news2025/2/25 18:13:14

目录

前言

整体思路

详细开发

1.左侧菜单的显隐控制

2.控制路由权限

补充权限控制

总结


前言

我这里是vue3开发的一个后台管理系统,所以涉及用户权限管理,以及页面权限等,其他模块部分可以查看专栏,这里只对怎么实现根据用户权限控制左侧菜单和路由。

        用户权限控制路由表和左侧菜单一般是带权限的系统的通用功能,在我还在上大学的时候,实现这个功能感觉很费劲,因为那时候对Vue一知半解,很多权限模模糊糊地实现了,实际上我现在也不能说全部了解,但是经过了几个项目,脑子里有了大概的思路。     

整体思路

用户权限我认为大可以分成两类:控制访问哪些页面,控制能执行哪些操作。

        前者要实现用户只能查看有权限的页面,比如,左侧菜单的菜单栏都是根据权限过滤的,跳转路由时要判断权限(路由守卫的工作),后者要做到用户只能操作有权限的功能,比如点击新建、修改按钮等。后者实现也很简单,好的方法是加一个权限的指令,哪个地方需要判断权限就调用,这里先只讨论前者的实现。

        如何实现这个功能,拆解为两部分,首先我们要知道用户有哪些菜单的权限,通常是通过接口获取,接着我们要知道用户有哪些路由的权限,比如'/login','/401','/user',这些页面,当然有时候401,500这些页面也会配置在白名单里,不受权限管理。

总结有两部分的权限:菜单权限,路由权限。

这里实现的功能如下:

用户有菜单A,B,C的权限,那么左侧菜单就显示ABC,

然后用户有路由 '/A','/B','/C','/D','/401','/login' 的权限,

那么用户可以访问这几个页面。

假如,用户没有'/B'的权限,那么点击菜单B也会跳到401页面。

  具体的功能明白了,那就开始详细的开发吧。

详细开发

我先说下我具体的思路。

        首先用户需要获取两部分权限,加上这两个接口,在哪里调用呢,肯定是左侧菜单渲染前,路由表生成前。

        前者应该在sidemenu的组件页进行,一般我们都会有这个页面对吧,根据获取到的左侧菜单,进行渲染,这样就完成了第一部分工作。

        至于路由权限的控制,那么肯定需要进行路由守卫的帮助,所以一般我会在router下进行,添加路由守卫拦截,每次router.push的时候,判断一下是否有权限。至于权限从哪里来,我这里是从用户的信息里获取到的,一般系统会有获取用户信息的接口吧,这里会有一些用户的个人配置和基本信息。

        我是在登录后,获取用户信息,存在了store里,然后nvabar里也获取了用户信息,执行同样的操作,然后这样就避免了每次刷新之后信息丢失的问题,当然用户信息可以放在storage或者cookie里,但是为了信息安全,还是别这样做了。

1.左侧菜单的显隐控制

左侧菜单的显隐我是根据权限显示的,没有权限则,没有这个菜单项,这样比较简单。

我显示一下我的数据格式,我获取到的菜单权限是一个数组,每一个对象里有对应路由的id和名字,我需要根据权限显示对应的菜单,如下:

 

这里是全部的路由表的数据:

 

其中我将需要权限的页面都放在了path='/'的children里。 

下面我实现的具体代码吧

const routes = ref()
onMounted(async () => {
  await getPermissionRoutes()
  routes.value = handleAdminMenus()
})

const handleAdminMenus = () => {
  const filteredRoutes = allRoutes.value.reduce((acc, route) => {
    if (route.path == '/') {
      const filteredChildren = route.children.filter((child) => {
        return adminMenus.value.some((item) => item.table_id === child.name)
      })

      if (filteredChildren.length > 0) {
        acc.push({ ...route, children: filteredChildren })
      }
    }

    return acc
  }, [])
  return filteredRoutes[0].children
}

let adminMenus = ref()
const getPermissionRoutes = async () => {
  await getAdminMenus().then((res) => {
    adminMenus.value = res

    console.log(adminMenus.value, res)
    return adminMenus.value
  })
}
<template>
  <div id="Sidebar" class="reset-menu-style">
    <!--logo-->
    <Logo v-if="settings.sidebarLogo" :collapse="!sidebar.opened" />
    <!--router menu-->
    <el-scrollbar>
      <el-menu
        class="el-menu-vertical"
        :collapse="!sidebar.opened"
        :default-active="activeMenu"
        :collapse-transition="false"
        mode="vertical"
      >
        <sidebar-item v-for="route in routes" :key="route.path" :item="route" :base-path="route.path" />
      </el-menu>
    </el-scrollbar>
  </div>
</template>

我上面主要是将获取到权限菜单和路由表做了一个对应比较,只让菜单显示有权限的路由,那么自然也只能点击有权限的路由了,比如菜单ABC,当然如果输入路径‘/404’,此刻也是可以跳转的,如何后面控制了路由守卫,如果没有404的页面权限,那么输入404 ,应该会跳到401页面,这里先说明一下。

接下来我们就实现这部分功能——只能根据权限进入相应的页面

2.控制路由权限

这里的还是比较简单的,主要就以下一些功能

当然这是比较简单的一个拦截,如果需要做一些其他操作比如,生成动态路由,或者添加权限等,都可以在【判断是否有当前权限】这之后进行。

import router from '@/router'
import { progressClose, progressStart } from '@/hooks/use-permission'
import { useBasicStore } from '@/store/basic'
import { langTitle } from '@/hooks/use-common'
import settings from '@/settings'
import { Message } from '@/hooks/use-element'
import { userInfoReq } from '@/api/user'
//路由进入前拦截
//to:将要进入的页面 vue-router4.0 不推荐使用next()
const whiteList = ['/login', '/404', '/401', '/loading'] // no redirect whitelist
router.beforeEach(async (to) => {
  progressStart()
  document.title = langTitle(to.meta?.title) // i18 page title
  const basicStore = useBasicStore()

  // not login
  if (!settings.isNeedLogin) {
    // basicStore.setFilterAsyncRoutes()
    return true
  }
  if (whiteList.indexOf(to.path) !== -1) {
    return true
  }

  // 是否已登录
  if (basicStore.token) {
    // 已登录
    if (to.path === '/login') {
      return '/'
    } else {
      const isGetUserInfo = basicStore.getUserInfo
      // 是否已获取用户信息和权限
      if (isGetUserInfo) {
        // 判断权限
        const userPermissions = basicStore.userPermissions || []
        const hasPermission = userPermissions.some((permission) => permission === to.path)
        if (hasPermission) {
          // basicStore.setFilterAsyncRoutes()
          return true
        } else {
          // 没有权限,跳转到 401 页面
          return '/401'
        }
      } else {
        try {
          // 获取用户信息和权限
          userInfoReq()
            .then((res) => {
              basicStore.setUserInfo({
                userInfo: res
              })
              // 判断权限
              const userPermissions = basicStore.userPermissions || []
              const hasPermission = userPermissions.some((permission) => permission === to.path)
              if (hasPermission) {
                // basicStore.setFilterAsyncRoutes()
                return true
              } else {
                // 没有权限,跳转到 401 页面
                return '/401'
              }
            })
            .catch((err) => {
              basicStore.setUserInfo({
                userInfo: {}
              })
              Message(err || '获取用户信息失败', 'error')
              return '/401'
            })
        } catch (err) {
          console.log('permission-catch-error', err)
          return `/login?redirect=${to.path}`
        }
      }
    }
  } else {
    // 未登录,跳转到登录页面
    if (!whiteList.includes(to.path)) {
      return `/login?redirect=${to.path}`
    } else {
      return true
    }
  }
})
//路由进入后拦截
router.afterEach(() => {
  progressClose()
})

这里留了一个口子,basicStore.setFilterAsyncRoutes(),如果登录后需要生成动态路由,则可以在这里进行。,但是我们的路由比较简单,就不做这些啦。

补充权限控制

这里补充一些登录后的路由跳转到权限控制

系统里我写了一个loading页面,系统登录后先跳到这个页面,这个页面会获取当前用户的菜单权限和用户权限,这个页面的作用如下:

如果当前菜单首页,那么这时会跳至首页。

如果当前有权限的菜单有BCD里没有默认跳转页面,那么就根据当前的菜单顺序,跳转至第一个菜单页,那么会去往B页面。

所以这个页面的目的也很明显啦,就是一个中转页,如果系统不小心去往了401,404,那么返回首页的时候,这个首页也会去往loading,这样就可以在用户没有首页权限时,也能有一个当前权限的【首页】,总要给用户一个页面的去处嘛。 

这些功能的实现也很简单,如下:

let adminMenus = ref()
onMounted(async () => {
  if (basicStore.adminMenus?.length > 0) {
    adminMenus.value = basicStore.adminMenus
    goToPath()
  } else {
    await getPermissionRoutes()
    goToPath()
  }
})

const goToPath = () => {
  const userPermissions = basicStore.userPermissions || []
  const hasPermission = userPermissions.some((permission) => permission === adminMenus.value[0].table_id)
  if (userPermissions.some((permission) => permission === '/homePage')) {
    router.push(`/homePage`)
  } else {
    if (adminMenus.value[0].type === 'page' && hasPermission) {
      router.push(adminMenus.value[0].table_id)
    } else if (hasPermission) {
      router.push(`/t${adminMenus.value[0].table_id}`)
    }
  }
}

总结

其实权限控制一般都跟业务关联很强,经常会在基础的上面那种权限控制上添加新的,所以很多时候在后期加新需求时,哪怕对权限很熟悉,也会有时候遇到一些bug,只要熟悉每一个组件的加载顺序,多加打印,就能慢慢解决~

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

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

相关文章

做亚马逊测评不知道怎么找客户?这才是亚马逊测评的正确打开方式!

如今的跨境电商内卷严重&#xff0c;花费大量资金做广告推广的效果却微乎其微&#xff0c;这也是亚马逊测评迅速崛起的最根本原因。做亚马逊测评是近年来兴起的一种方式&#xff0c;许多卖家都需要大量的测评来提高自己的产品排名和信誉度。很多兄弟最近来问龙哥亚马逊测评怎么…

Mysql For Navicate (老韩)

Navicate创建数据库 先创建一个数据库;然后在数据库中创建一张表;在表格当中填入相应的属性字段;打开表, 然后填入相应的实例字段; – 使用数据库图形化App和使用指令来进行操作各有各的好处和利弊; 数据库的三层结构(破除MySQL神秘) 所谓安装Mysql数据库, 就是在主机安装一…

网工内推 | 网络服务工程师,HCIE认证优先,带薪年假,年终奖

01 高凌信息 招聘岗位&#xff1a;服务工程师&#xff08;珠海&#xff09; 职责描述&#xff1a; 1、负责华为数通&#xff08;交换机、路由器&#xff09;、IT&#xff08;服务器、存储&#xff09;等任一或多个产品领域的项目实施交付&#xff1b; 2、独立完成华为数通&…

搭建FTP服务器与计算机端口介绍

FTP介绍 FTP&#xff08;File Transfer Protocol&#xff09;是一种用于在计算机网络上进行文件传输的协议。它允许用户通过客户端与服务器进行通信&#xff0c;从服务器下载文件或将文件上传到服务器。 FTP使用客户端-服务器模型。用户使用FTP客户端软件连接到FTP服务器&…

常用的 linux 命令

常用的 linux 命令 1.从其他机器拷贝文件夹2.查看哪个程序在用特定端口3.实时监控日志文件内容4.查看指定用户拥有的进程5.查看磁盘空间使用情况6.文件搜索which&#xff08;whereis&#xff09; 显示系统命令所在目录find 查找任何文件或目录1&#xff09; 根据文件名称查找2)…

未来10年,C++5个非常有前景的就业方向

一、后台服务器开发 1.1 C后台所需要具备的技能 如果要从事C后台服务器开发&#xff0c;那么先要了解C后台服务器需要具备的技能。 所需技能可以参考如下&#xff1a; 软件基础&#xff08;数据结构与算法&#xff0c;设计模式&#xff0c;C新特性&#xff0c;Linux工程管理&…

Oracle统计信息的魔力

文章目录 一、Oracle统计信息的概述二、统计信息主要包括以下内容三、收集统计信息的方法使用dbms_stats 程序包手动收集收集的是系统统计信息 四、 案例 一、Oracle统计信息的概述 Oracle统计信息是数据库性能调优的关键组成部分&#xff0c;它为数据库优化器提供了关于表、索…

图像ISP处理——自动对焦AF算法

自动对焦算法是在数码相机、摄像机和其他图像采集设备中常见的技术之一&#xff0c;它通过调整镜头位置或其他光学参数来确保拍摄的图像在焦点上清晰。 以下是一些常见的自动对焦算法&#xff1a; 对比度检测对焦&#xff08;Contrast Detection Autofocus&#xff0c;CDAF&am…

掌握激活函数(一):深度学习的成功之源

文章目录 引言基本概念常用激活函数举例Sigmoid激活函数公式Sigmoid函数的数学特性示例基于NumPy和PyTorch实现Sigmoid函数将Sigmoid函数应用于二分类任务 Sigmoid激活函数的局限性举例 ReLU激活函数公式ReLU函数的数学特性ReLU函数的特点示例基于NumPy和PyTorch实现ReLU函数搭…

Python+OpenGL绘制3D模型(四)绘制线段

系列文章 一、逆向工程 Sketchup 逆向工程&#xff08;一&#xff09;破解.skp文件数据结构 Sketchup 逆向工程&#xff08;二&#xff09;分析三维模型数据结构 Sketchup 逆向工程&#xff08;三&#xff09;软件逆向工程从何处入手 Sketchup 逆向工程&#xff08;四&#xf…

[RoarCTF2019] TankGame

不多说&#xff0c;用dnspy反编译data文件夹中的Assembly-CSharp文件 使用分析器分析一下可疑的FlagText 发现其在WinGame中被调用&#xff0c;跟进WinGame函数 public static void WinGame(){if (!MapManager.winGame && (MapManager.nDestroyNum 4 || MapManager.n…

DevOps持续交付之容器化CICD流水线

DevOps持续交付 随着DevOps⼤规模化的落地和应⽤&#xff0c;持续集成以及持续交付已经是⼀种常态的。CI指的是持续集成&#xff0c;使⽤的开源⼯具是Jenkins&#xff0c;CD指的是持续交付和持续部署&#xff0c;⼀个完整的软件开发⽣命周期为: 主要流程可以具体为: 构建阶段…

JS 嵌套循环之退出顶层循环

我们常常写循环的时候&#xff0c;可能会遇到嵌套循环&#xff0c;如果出现退出循环&#xff0c;一层还好&#xff0c;多层循环就费劲了&#xff0c;传统做法是加 flag&#xff0c;如下&#xff1a; for (let i 0; i < 10; i) {let flag falsefor (let j 0; j < 5; j…

C++ BuilderXE10 关于Intraweb关于IWTemplateProcessorHTML1操作

1、端口设置,port参数修改端口号。 2、初始化设置成ciMultiThreaded。这样可以避免ADO组件的加载错误。 3、IWTemplateProcessorHTML1设置&#xff0c; IWForm1->LayoutMgr IWTemplateProcessorHTML1;//关联模板(IWForm1. html) IWTemplateProcessorHTML1->RenderStyles…

【Recruitment Mercedes Benz】

Network I) JDII) IPv4与IPv6之间的区别是什么III) was advices3.1&#xff09; 防火墙&#xff0c;配置&#xff0c;数据的in/out (data flow in or flow out)3.2&#xff09; 域名&#xff0c;网址&#xff0c;端口3.3) 三次握手&#xff0c;四次挥手3.4) TCP/IP, 几层协议&a…

原生微信小程序如何动态配置主题颜色及如何调用子组件的方法

一、最终效果 二、步骤 1、在初始化进入项目时&#xff0c;获取当前主题色 2、把主题色定义成全局变量&#xff08;即在app.js中设置&#xff09; 3、tabBar也需要定义全局变量&#xff0c;在首页时需要重新赋值 三、具体实现 1、app.js onLaunch () {//获取主题数据this.set…

Go 泛型之明确使用时机与泛型实现原理

Go 泛型之明确使用时机与泛型实现原理 文章目录 Go 泛型之明确使用时机与泛型实现原理一、引入二、何时适合使用泛型&#xff1f;场景一&#xff1a;编写通用数据结构时场景二&#xff1a;函数操作的是 Go 原生的容器类型时场景三&#xff1a;不同类型实现一些方法的逻辑相同时…

Xshell 从github克隆项目:使用ssh方式。

接上文&#xff1a; https://blog.csdn.net/liu834189447/article/details/135247868 是能克隆项目了&#xff0c;但是速度太磕碜了&#xff0c;磕碜到难以直视。 找到另外一种办法&#xff0c;使用SSH克隆项目 速度嘎嘎猛。 首先得能进得去github网站&#xff0c;不能点上边…

电缆故障测试仪的其他用途是什么?

电缆故障测试仪是电力行业非常重要的设备。它可以帮助电缆维护人员快速准确地判断电缆故障点和类型&#xff0c;帮助电缆维护人员快速维护和维护电缆&#xff0c;从而减少电缆故障引起的安全事故。此外&#xff0c;电缆故障测试仪的其他用途是什么&#xff1f;现在让我们一起分…

Download Monitor Email Lock下载监控器邮件锁插件

打开Download Monitor Email Lock下载监控器邮件锁插件 Download Monitor Email Lock下载监控器邮件锁插件下载监视器的电子邮件锁定扩展允许您要求用户在获得下载访问权限之前填写他们的电子邮件地址。 Download Monitor Email Lock下载监控器邮件锁插件用法 安装扩展程序后…