茫茫人海遇见了你,不早也不晚。关于Admin Work 框架中"按钮级权限"功能架构的思考与实现

简介: 茫茫人海遇见了你,不早也不晚。关于Admin Work 框架中"按钮级权限"功能架构的思考与实现

“人生是为心的修行而设立的道场。人生的目的就是在灾难和幸运才考验中磨炼自己的心志,磨炼灵魂,造就一颗美丽的心灵”

----来自《稻盛和夫给年轻人的忠告》

前言

   在VueAdminWork框架中一直有一个功能至今还没实现,就是关于 "按钮级权限"也可以叫做 "功能点权限" 地实现。

   一开始也想实现这个功能,随便从网上找几个类似的指令集成进去就好,但是我觉得这样千篇一律也没有什么意思,就想着能不能把这个功能做的尽量完善、方便、扩展性强点。最近正好有时间,就想着如何把这个功能实现一下。


总体功能概述

   VueAdminWork的权限是基于RBAC权限模型设计而来。什么是RBAC大家可以网上查阅相关的资料,网上有很多这样的介绍。

不同角色的用户拥有不同的菜单权限。所以在这一模型下,我们得把按钮都依附于页面或者菜单下。

所以我们打算设计成两种都能控制的形式

  • 基于后端的控制方式
  • 基于前端的控制方式

基于后端的就是某个用户拥有不同的角色就相当于拥有不同的菜单权限,拥有不同的菜单那么就拥有不同的按钮。这样就可以实现了此功能

但是,我们还得考虑一点就是不是所有的页面都是受角色控制的,一些公共的页面,如个人中心,登录,工作台等,都是不受控制的,在这一环境下,我们就得使用 "基于前端的控制方式"


基于后端的控制方式具体实现思路

  1. 根据当前登录用户的角色获取菜单并且把所有的按钮查询出来放在菜单数据下,然后再通过一系列前端的处理,放入 `pinia` 状态中
  2. 根据按钮的不同展示位置属性进行分类,
    有的按钮是要放在页面最顶部,如:新增;
    有的按钮是放在 表格 中用来操作每一行的数据,如:编辑、删除等
  3. 在分类好之后,通过特定的组件容器把按钮展示出来。

说起来不算难,可是要真正实现这一功能,还是需要一点时间的。这里我们还是通过 mock 进行接口数据的模拟

先来看一下数据结构

{
    menuUrl: '/system',
    menuName: '系统管理',
    iconPrefix: 'iconfont',
    icon: 'setting',
    parentPath: '',
    children: [
      {
        parentPath: '/system',
        menuUrl: '/system/department',
        menuName: '部门管理',
        cacheable: true,
        buttonList: [
          {
            name: '添加',
            code: 'add',
            // admin角色所能展示的按钮
            roleCode: 'ROLE_admin',
            placement: 'top',
            type: 'primary',
          },
          {
            name: '编辑',
            code: 'update',
            // editor角色所能展示的按钮
            roleCode: 'ROLE_editor',
            placement: 'tableLine',
            type: 'warning',
          },
          {
            name: '删除',
            code: 'delete',
            // 所有角色所能展示的按钮
            roleCode: 'ROLE_all',
            placement: 'tableLine',
            type: 'error',
          },
        ],
      },
     }

拿到数据之后我们进行分类

/**
     * 根据当前用户的 roleCode 返回 某个 path 下所有的 button
     * @param key 路由 path
     * @returns buttons
     */
    getButtonsListByRoleCode(key: string) {
      const userStore = useUserStore()
      const userRoleCode = userStore.userRoleCode
      const result = this.permissionButtonList.find((it) => it.key === key)
      if (result) {
        if (Array.isArray(result.buttonList) && result.buttonList.length > 0) {
          return result.buttonList.filter(
            (it) => userRoleCode.includes(it.roleCode) || it.roleCode === 'ROLE_all'
          )
        }
        return []
      } else {
        return []
      }
    },
    /**
     * 根据按钮的位置进行归类
     * @param key 路由 path
     * @returns buttons
     */
    getButtonListByPlacement(key: string) {
      const resultButtonList = this.getButtonsListByRoleCode(key)
      return resultButtonList.reduce((pre, cur) => {
        if (!(pre as any)[cur.placement]) {
          ;(pre as any)[cur.placement] = []
        }
        ;(pre as any)[cur.placement].push(cur)
        return pre
      }, {} as ButtonPlacement)
    },

然后再在页面上进行展示

// 动态展示
tableColumns.push({
    title: '操作',
    key: 'actions',
    align: 'center',
    render: (rowData) => {
      return useRenderAction(
        buttonModel.tableLine?.map((it) => {
          return {
            label: it.name,
            // onClick: eval(it.code + `.bind(null,rowData)`),
            onClick: () => {
              switch (it.code) {
                case 'update':
                  onUpdateItem(rowData)
                  break
                case 'delete':
                  onDeleteItem(rowData)
                  break
              }
            },
            type: it.type,
          } as TableActionModel
        }) || []
      )
    },
  })
// 通过组件容器进行展示
<PermissionButtons :buttons="topButtons" @click="onPermissionButtonClick" />

来看一下效果

ROLE_admin 所有的按钮4edc953e2c684bbe819ffa954c899c08.png

ROLE_editor 所有的按钮4edc953e2c684bbe819ffa954c899c08.png这样基本的功能算是实现了


基于前端的控制方式具体实现思路

这种方式下比较简单,就通过 v-permission 指令实现就好,用法也比较简单,和普通的指令用法一样

<template>
    // 指令接收的参数如果是多个的话可以是一个数组,如果只有一个就直接是一个字符串就好
    <DeleteButton v-permission="['ROLE_admin', 'ROLE_editor']" />
    <DeleteButton v-permission="'ROLE_admin'" />
  </template>


写在最后

今天的内容比较长,希望大家可以认真的看一下,应该会有收获的。在这种方式下,如果以后对某个用户进行权限控制也是比较方便扩展的,根据当前登录用户的 id 和 角色查询出不同的按钮。当然这还需要前端进一步的处理。此功能我们以后再讲如何实现


相关文章
|
12天前
|
分布式计算 大数据 数据处理
经典大数据处理框架与通用架构对比
【6月更文挑战第15天】本文介绍Apache Beam是谷歌开源的统一数据处理框架,提供可移植API,支持批处理和流处理。与其他架构相比,Lambda和Kappa分别专注于实时和流处理,而Beam在两者之间提供平衡,具备高实时性和数据一致性,但复杂性较高。选择架构应基于业务需求和场景。
24 3
经典大数据处理框架与通用架构对比
|
2天前
|
前端开发 Java 开发工具
Java医院绩效考核系统源码:关于医院绩效考核系统的技术架构、系统功能、如何选择医院绩效考核管理系统
系统开发环境 开发语言:java 技术架构:B/S架构 开发工具:maven、Visual Studio Code 前端框架:avue 后端框架:springboot、mybaits 数 据 库:MySQL
18 4
Java医院绩效考核系统源码:关于医院绩效考核系统的技术架构、系统功能、如何选择医院绩效考核管理系统
|
6天前
|
存储 数据采集 数据挖掘
“湖仓一体架构及其应用”写作框架,系统架构设计师
随着5G、大数据、人工智能、物联网等技术的不断成熟,各行各业的业务场景日益复杂,企业数据呈现出大规模、多样性的特点,特别是非结构化数据呈现出爆发式增长趋势。在这一背景下,企业数据管理不再局限于传统的结构化OLTP(On-Line Transaction Processing)数据交易过程,而是提出了多样化、异质性数据的实时处理要求。传统的数据湖(Data Lake)在事务一致性及实时处理方面有所欠缺,而数据仓库(Data Warehouse)也无法应对高并发、多数据类型的处理。因此,支持事务一致性、提供高并发实时处理及分析能力的湖仓一体(Lake House)架构应运而生。湖仓一体架构在成本、
|
2天前
|
存储 消息中间件 API
“论微服务架构及其应用”写作框架,软考高级,系统架构设计师
论微服务架构及其应用近年来,随着互联网行业的迅猛发展,公司或组织业务的不断扩张,需求的快速变化以及用户量的不断增加,传统的单块(Monolithic)软件架构面临着越来越多的挑战,已逐渐无法适应互联网时代对软件的要求。在这一背景下,微服务架构模式(MicroserviceArchitecturePattern)逐渐流行,它强调将单一业务功能开发成微服务的形式,每个微服务运行在一个进程中;采用HTTP等通用协议和轻量级API实现微服务之间的协作与通信。这些微服务可以使用不同的开发语言以及不同数据存储技术,能够通过自动化部署工具独立发布,并保持最低限制的集中式管理。
|
3天前
|
Java 数据库连接 API
“论数据访问层设计技术及其应用”写作框架,系统架构设计师
在信息系统的开发与建设中,分层设计是一种常见的架构设计方法,区分层次的目的是为了实现“高内聚低耦合”的思想。分层设计能有效简化系统复杂性,使设计结构清晰,便于提高复用能力和产品维护能力。一种常见的层次划分模型是将信息系统分为表现层、业务逻辑层和数据访问层。信息系统一般以数据为中心,数据访问层的设计是系统设计中的重要内容。数据访问层需要针对需求,提供对数据源读写的访问接口;在保障性能的前提下,数据访问层应具有良好的封装性、可移植性,以及数据库无关性。
“论数据访问层设计技术及其应用”写作框架,系统架构设计师
|
9天前
|
缓存 NoSQL Java
在 SSM 架构(Spring + SpringMVC + MyBatis)中,可以通过 Spring 的注解式缓存来实现 Redis 缓存功能
【6月更文挑战第18天】在SSM(Spring+SpringMVC+MyBatis)中集成Redis缓存,涉及以下步骤:添加Spring Boot的`spring-boot-starter-data-redis`依赖;配置Redis连接池(如JedisPoolConfig)和连接工厂;在Service层使用`@Cacheable`注解标记缓存方法,指定缓存名和键生成策略;最后,在主配置类启用缓存注解。通过这些步骤,可以利用Spring的注解实现Redis缓存。
28 2
|
14天前
|
前端开发 JavaScript 测试技术
web前端语言框架:探索现代前端开发的核心架构
web前端语言框架:探索现代前端开发的核心架构
20 4
|
2天前
|
边缘计算 Cloud Native IDE
“论SOA在企业集成架构设计中的应用”写作框架,系统架构设计师
企业应用集成(Enterprise Application Integration, EAI)是每个企业都必须要面对的实际问题。面向服务的企业应用集成是一种基于面向服务体系结构(Service-OrientedArchitecture,SOA)的新型企业应用集成技术,强调将企业和组织内部的资源和业务功能暴露为服务,实现资源共享和系统之间的互操作性,并支持快速地将新的应用以服务的形式加入到已有的集成环境中,增强企业IT环境的灵活性。
|
2天前
|
运维 监控 Cloud Native
“论云原生架构及其应用”写作框架,系统架构设计师
近年来,随着数字化转型不断深入,科技创新与业务发展不断融合,各行各业正在从大工业时代的固化范式进化成面向创新型组织与灵活型业务的崭新模式。在这一背景下,以容器和微服务架构为代表的云原生技术作为云计算服务的新模式,已经逐渐成为企业持续发展的主流选择。云原生架构是基于云原生技术的一组架构原则和设计模式的集合,旨在将云应用中的非业务代码部分进行最大化剥离,从而让云设施接管应用中原有的大量非功能特性(如弹性、韧性、安全、可观测性、灰度等),使业务不再有非功能性业务中断困扰的同时,具备轻量、敏捷、高度自动化的特点。云原生架构有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用
|
8天前
|
JavaScript 前端开发 Java
信息打点-JS架构&框架识别&泄漏提取&API接口枚举&FUZZ&插件项目
信息打点-JS架构&框架识别&泄漏提取&API接口枚举&FUZZ&插件项目

热门文章

最新文章