后台管理系统的权限自动化实践
date
Apr 17, 2022
slug
boss-auto-auth
status
Published
tags
优化
summary
有关权限自动化的实践在我们项目中已经落地了一段时间,运行的也很顺利了,下面就来分享一下我们项目运行时遇到了什么问题,以及我们是怎么解决的。
type
Post
前言
有关权限自动化的实践在我们项目中已经落地了一段时间,运行的也很顺利了,下面就来分享一下我们项目运行时遇到了什么问题,以及我们是怎么解决的。
项目背景
我们后台管理权限采用的是权限设计模型中的
RBAC(Role-Based Access Control)
也就是基于 角色 的权限控制。在实际的项目中应用的架构图基本上是这样的:
flowchart LR
menu1[菜单模块]
menu2[菜单模块]
menu11[菜单模块]
menu21[菜单模块]
api2[接口权限] --> menu1
api3[接口权限] --> menu1
api4[接口权限] --> menu2
api5[接口权限] --> menu2
api11[接口权限] --> menu11
api21[接口权限] --> menu11
api41[接口权限] --> menu21
api51[接口权限] --> menu21
menu1 --> role1
menu2 --> role1
role11[角色]
role1[角色]
menu11 --> role11
menu21 --> role11
user[用户]
role1 --> user
role11 --> user
但这样的方案在实际应用中会有那些问题?
- 菜单模块:实际对应的就是一个路由,路由对应的一个页面
- 前端模块的显示就是一个
key
,根据这个key
,来判断当前用户信息中是否存在该key
,从而决定前端的显示,目前该key
,是前端开发在开发中自己定义的一个 唯一字符串
我们生成环境的角色权限都是由 产品、运营 来配置的,而他们只清楚每个角色应该有哪些菜单模块的权限,不知道菜单模块对接着那些接口权限,而页面中对应那些接口权限只有前端知道,这就造成一个问题,每当有新增菜单模块的需求上线是,前端需要告诉产品,新增了那些菜单对应的
key
,以及 key
对应这那些接口权限。而对于产品和运营来讲,他们只关心角色和菜单之间的关系,至于菜单和接口之间的关系对他们来说是负担,而当后台的管理系统用的人和覆盖的国家线越来越多时,沟通成本和理解成本也会越来越高。
flowchart LR
menu1[菜单模块]
menu2[菜单模块]
menu11[菜单模块]
menu21[菜单模块]
api2[接口权限] --> menu1
api3[接口权限] --> menu1
api4[接口权限] --> menu2
api5[接口权限] --> menu2
api11[接口权限] --> menu11
api21[接口权限] --> menu11
api41[接口权限] --> menu21
api51[接口权限] --> menu21
role11[角色]
role1[角色]
subgraph 实际关心
menu1 --> role1
menu2 --> role1
menu11 --> role11
menu21 --> role11
user[用户]
role1 --> user
role11 --> user
end
解决问题
那么关于菜单和接口之间的关联关系,可不可以任何人不需要关心呢?
可以。方案是通过 扫描 项目中的每个页面所调用的接口,然后生成一个页面相关的
JSON
文件,然后根据该文件和项目中菜单配置文件生成一个新的文件,该文件的 key
是由菜单的路径标题拼接后hash
生成的唯一 key
。这里有一个基本实现扫描的脚本的 例子,可以参考一下,执行node index.js
就会扫描项目并生成一个menu-config.json
文件。
扫描项目生成的 文件权限描述 类似这样:
{
"src/views/aaa/bbb/test.tsx": {
"authApiList": [
{
"method": "POST",
"api": "/xxx/ccc/aaa",
"apiName": "testApi"
},
{
"method": "POST",
"api": "/xxx/ccc/bbb",
"apiName": "test1Api"
}
],
"elementList": [],
"authElementList": []
},
// ...
}
项目中 菜单配置:
const sideBarList = [
{
name: 'test menu',
type: 'MENU',
path: '/test',
children: [
{
name: 'test1',
path: '/aaa/bbb',
componentPath: '@/views/aaa/bbb',
},
]
}
//...
]
运行时将 文件权限描述 和 菜单配置 通过 componentPath 匹配后合并为一个新的文件,有了这份
JSON
,就可以实现 自动配置接口、自动显示对应模块、更直观的以树形结构 直观的显示权限配置。[
{
name: 'test menu',
type: 'MENU',
allAuthList: ['21334', '4567']
path: '/test',
children: [
{
name: 'test1',
path: '/aaa/bbb',
key: '21334',
componentPath: '@/views/aaa/bbb',
authApiList: [
{
method: "POST",
api: "/xxx/ccc/aaa",
apiName: "testApi"
},
{
method: "POST",
api: "/xxx/ccc/bbb",
apiName: "test1Api"
}
]
},
]
}
//...
]
结构图如下:
flowchart LR
subgraph 菜单模块
menu1[菜单模块]
menu2[菜单模块]
menu11[菜单模块]
menu21[菜单模块]
api2[接口权限] --> menu1
api3[接口权限] --> menu1
api4[接口权限] --> menu2
api5[接口权限] --> menu2
api11[接口权限] --> menu11
api21[接口权限] --> menu11
api41[接口权限] --> menu21
api51[接口权限] --> menu21
end
menu1 --> role1
menu2 --> role1
role11[角色]
role1[角色]
menu11 --> role11
menu21 --> role11
subgraph 实际关心
user[用户]
role1 --> user
role11 --> user
end
scan[扫描遍历分析]
project[项目目录]
buildMenuConfig[生成文件权限描述 JSON]
menuList[菜单文件配置]
menuAuthList[菜单文件权限配置]
pageFolder[页面文件夹]
project --> menuList
project --> pageFolder
pageFolder --> scan
scan --> buildMenuConfig
subgraph 关键
menuList --> menuAuthList
buildMenuConfig --> menuAuthList
end
menuAuthList --> showMenu[模块显示级别展示]
menuAuthList --> operateRole[简易化操作角色页面]
menuAuthList --> autoConfig[自动配置接口菜单模块权限]
autoConfig --> 菜单模块
最终效果
改造前
- 配置繁琐易出错
- 权限跨国家线迁移困难
- 前端/测试/产品都需要关心菜单对应那些接口
- 有认知成本
- 前端需定义
key
且不统一
改造后
- 无需配置
- 一键模块权限更新
- 所有人无需关心
- 无
- 自动生成
key
简化了新增菜单需求的权限相关流程,上线是只需要点击一个 自动更新的按钮 即可,无需之前繁琐的配置菜单对应那些接口权限。
总结
枯燥无味的后台管理系统也能探索和优化,只要保有一个提效(懒惰)的心。