首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >茫茫人海遇见了你,不早也不晚。关于Admin Work 框架中"按钮级权限"功能架构的思考与实现

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

作者头像
用户9078190
发布2022-10-28 18:43:40
发布2022-10-28 18:43:40
3000
举报
文章被收录于专栏:知码前端知码前端

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

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

01前言

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

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

02总体功能概述

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

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

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

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

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

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

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

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

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

先来看一下数据结构

代码语言:javascript
复制
{
    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',
          },
        ],
      },
     }

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

代码语言:javascript
复制
/**
     * 根据当前用户的 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)
    },

然后再在页面上进行展示

代码语言:javascript
复制
// 动态展示
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
        }) || []
      )
    },
  })
代码语言:javascript
复制
// 通过组件容器进行展示
<PermissionButtons :buttons="topButtons" @click="onPermissionButtonClick" />

来看一下效果

ROLE_admin 所有的按钮

ROLE_editor 所有的按钮

这样基本的功能算是实现了

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

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

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

05写在最后

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2022-01-21,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 知码前端 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 01前言
  • 02总体功能概述
  • 03基于后端的控制方式具体实现思路
  • 04基于前端的控制方式具体实现思路
  • 05写在最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档