茫茫人海遇见了你,不早也不晚。关于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 和 角色查询出不同的按钮。当然这还需要前端进一步的处理。此功能我们以后再讲如何实现


相关文章
|
2月前
|
存储 边缘计算 Cloud Native
“论模型驱动架构设计方法及其应用”写作框架,软考高级,系统架构设计师
模型驱动架构设计是一种用于应用系统开发的软件设计方法,以模型构造、模型转换和精化为核心,提供了一套软件设计的指导规范。在模型驱动架构环境下,通过创建出机器可读和高度抽象的模型实现对不同问题域的描述,这些模型独立于实现技术,以标准化的方式储存,利用模型转换策略来驱动包括分析、设计和实现等在内的整个软件开发过程。
|
1月前
|
负载均衡 监控 Kubernetes
Service Mesh 是一种用于处理服务间通信的基础设施层,它通常与微服务架构一起使用,以提供诸如服务发现、负载均衡、熔断、监控、追踪和安全性等功能。
Service Mesh 是一种用于处理服务间通信的基础设施层,它通常与微服务架构一起使用,以提供诸如服务发现、负载均衡、熔断、监控、追踪和安全性等功能。
|
13天前
|
监控 架构师 项目管理
项目管理架构师的角色与职责:构建高效项目交付框架
【8月更文第7天】在当今快速变化的商业环境中,组织需要灵活高效的项目交付机制来应对不断出现的新挑战。项目管理架构师(Project Management Architect, PMA)作为一种新兴的角色,在确保项目成功交付方面扮演着至关重要的角色。本文将探讨PMA的核心职责,以及他们如何通过设计和实施项目管理流程来提高项目的可扩展性和适应性,并通过有效的项目治理来提升团队的整体表现。
31 0
|
1月前
|
消息中间件 Java 开发者
Spring Cloud微服务框架:构建高可用、分布式系统的现代架构
Spring Cloud是一个开源的微服务框架,旨在帮助开发者快速构建在分布式系统环境中运行的服务。它提供了一系列工具,用于在分布式系统中配置、服务发现、断路器、智能路由、微代理、控制总线、一次性令牌、全局锁、领导选举、分布式会话、集群状态等领域的支持。
119 5
|
20天前
|
开发框架 前端开发 关系型数据库
ABP框架使用Mysql数据库,以及基于SQLServer创建Mysql数据库的架构和数据
ABP框架使用Mysql数据库,以及基于SQLServer创建Mysql数据库的架构和数据
|
2月前
|
存储 消息中间件 API
“论微服务架构及其应用”写作框架,软考高级,系统架构设计师
论微服务架构及其应用近年来,随着互联网行业的迅猛发展,公司或组织业务的不断扩张,需求的快速变化以及用户量的不断增加,传统的单块(Monolithic)软件架构面临着越来越多的挑战,已逐渐无法适应互联网时代对软件的要求。在这一背景下,微服务架构模式(MicroserviceArchitecturePattern)逐渐流行,它强调将单一业务功能开发成微服务的形式,每个微服务运行在一个进程中;采用HTTP等通用协议和轻量级API实现微服务之间的协作与通信。这些微服务可以使用不同的开发语言以及不同数据存储技术,能够通过自动化部署工具独立发布,并保持最低限制的集中式管理。
|
1月前
|
负载均衡 Java Linux
黑马头条01,环境搭建,今日头条的介绍,今日头条的功能架构图,技术栈的说明,服务层,nacos(奶靠丝)安装,安装在Linux服务器上环境准备,
黑马头条01,环境搭建,今日头条的介绍,今日头条的功能架构图,技术栈的说明,服务层,nacos(奶靠丝)安装,安装在Linux服务器上环境准备,
|
1月前
|
缓存 Devops 微服务
微服务01好处,随着代码越多耦合度越多,升级维护困难,微服务技术栈,异步通信技术,缓存技术,DevOps技术,搜索技术,单体架构,分布式架构将业务功能进行拆分,部署时费劲,集连失败如何解决
微服务01好处,随着代码越多耦合度越多,升级维护困难,微服务技术栈,异步通信技术,缓存技术,DevOps技术,搜索技术,单体架构,分布式架构将业务功能进行拆分,部署时费劲,集连失败如何解决
|
2月前
|
边缘计算 Cloud Native IDE
“论SOA在企业集成架构设计中的应用”写作框架,系统架构设计师
企业应用集成(Enterprise Application Integration, EAI)是每个企业都必须要面对的实际问题。面向服务的企业应用集成是一种基于面向服务体系结构(Service-OrientedArchitecture,SOA)的新型企业应用集成技术,强调将企业和组织内部的资源和业务功能暴露为服务,实现资源共享和系统之间的互操作性,并支持快速地将新的应用以服务的形式加入到已有的集成环境中,增强企业IT环境的灵活性。
|
2月前
|
运维 监控 Cloud Native
“论云原生架构及其应用”写作框架,系统架构设计师
近年来,随着数字化转型不断深入,科技创新与业务发展不断融合,各行各业正在从大工业时代的固化范式进化成面向创新型组织与灵活型业务的崭新模式。在这一背景下,以容器和微服务架构为代表的云原生技术作为云计算服务的新模式,已经逐渐成为企业持续发展的主流选择。云原生架构是基于云原生技术的一组架构原则和设计模式的集合,旨在将云应用中的非业务代码部分进行最大化剥离,从而让云设施接管应用中原有的大量非功能特性(如弹性、韧性、安全、可观测性、灰度等),使业务不再有非功能性业务中断困扰的同时,具备轻量、敏捷、高度自动化的特点。云原生架构有利于各组织在公有云、私有云和混合云等新型动态环境中,构建和运行可弹性扩展的应用