权限设计
为什么要有权限设计?
对于一个系统,有多个模块,在需要给不同的用户分配不同的模块权限的场景下,就需要进行权限设计,按需给用户划分对应的权限。比如一个企业系统有用户管理模块、财务管理模块、库存管理模块……对于财务人员来说,只需要财务管理模块的相应权限,不应该分配其他模块的权限;而对于库存人员来说,只需要库存管理模块的权限;对于负责人来说,可能需要所有的模块权限。
权限设计的思路
最开始,用户比较少,就可以用最直观的方式,一个用户需要什么功能,就给他分配功能的权限。
但是随着企业人数逐渐变多,需要分配权限的用户越来越多,刚开始 10 个用户的时候可以手动分配,但是 1000 个用户再手动分配就会变得繁琐低效。
通过对功能分配的观察,有很多用户会分配相同或相似的权限,比如对负责人来说,所有的功能权限都要勾选,每次全都勾选十分复杂,因此可以把这些功能打包起来,成为一个“功能集”。因此可以定义一个“角色”拥有一组功能,就将用户和功能完成了解耦,只需要给用户分配一个角色,便拥有了这个角色对应的所有功能。
如何进行权限设计?
权限设计分为功能权限和数据权限
功能权限:用户登录系统后能看到什么模块,能看到哪些页面
数据权限:用户在某个模块里能看到哪些数据
下面以实际项目为例,介绍项目中如何进行权限设计。
背景信息
项目背景为建设文旅产品,以较为有名的“一机游云南”为例,我们要建设一个“一机游云南”的产品,这个产品包含后台管理系统和小程序,可以在后台编辑活动、咨询、公告等模块,具体的模块下既可以编辑云南省的相关信息,也可以编辑下属景区的信息。如可以编辑云南省的公告信息,也可以编辑下属丽江景区的公告信息。
由于模块众多,且景区众多,让一个管理员来管理工作量显然巨大,因此可以给不同景区和不同模块各自分配相应的管理员来管理。比如可以分配一个管理员拥有丽江、大理的公告模块和活动模块,也可以分配另一个管理员拥有玉龙雪山的咨询、景区信息模块。如果一个管理员没有被分配任何一个景区的公告模块权限,那他就无法看到公告模块,如果只分配了丽江的公告模块权限,那么在公告模块下也只能看到和编辑丽江的信息。
权限系统示意图
采用 RBAC 的思想,用户->角色→权限相分离,用户可以配置多个角色,权限为所有角色的合集
页面设计
由于页面设计相对固定,没有频繁变更功能模块的需求,因此通过配置文件的方式实现。
1module:
2 # 有二级页面
3 - tag: "page_management" # module tag 必须全局唯一
4 # saas、私有化-全域和私有化景区文旅通都显示
5 category:
6 - 0
7 - 1
8 - 2
9 name: "页面管理"
10 sub:
11 - tag: "page_content"
12 name: "页面内容管理"
13 access:
14 - tag: "info"
15 name: "查看"
16 url:
17 - "/tourism_inner/v1/management/info"
18 - "/tourism_inner/v1/management/list"
19 - tag: "edit"
20 name: "编辑"
21 url:
22 - "/tourism_inner/v1/management/edit"
23 - tag: "page_layout"
24 name: "页面布局管理"
25 access:
26 - tag: "info"
27 name: "查看"
28 url:
29 - "/tourism_inner/v1/layout/add"
30 # 没有二级页面
31 - tag: "scenic_management"
32 name: "景区管理"
33 # 只有景区文旅通显示
34 category:
35 - 1
36 access:
37 - tag: "edit"
38 name: "编辑"
39 url:
40 - "/tourism_inner/v1/scenic/update"
角色设计
设计角色表如下:
1CREATE TABLE `role` (
2 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT COMMENT '自增id',
3 `product_id` bigint(20) NOT NULL COMMENT '产品id',
4 `name` varchar(20) NOT NULL COMMENT '角色名',
5 `category` tinyint(1) NOT NULL COMMENT '类型: 1全域角色 2景区角色',
6 `content` text NOT NULL COMMENT '角色内容',
7 `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态: 1有效 0无效',
8 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
9 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
10 PRIMARY KEY (`id`),
11 KEY `idx_product` (`product_id`)
12) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='角色表';
content:为该角色关联的模块信息,举例如下:
1[
2 {
3 "tag":"page_content",
4 "access":["info", "edit"]
5 },
6 {
7 "tag":"page_layout",
8 "access":["edit"]
9 },
10 {
11 "tag": "scenic_management",
12 "access": ["edit"]
13 }
14]
该角色有 页面管理→页面内容管理 的查看和编辑权限,页面管理→页面布局管理 的查看权限。
用户角色关联设计
用户角色授权表为:
1CREATE TABLE `authorization` (
2 `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
3 `authorizer_id` bigint(20) NOT NULL COMMENT '用户id',
4 `role_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '角色id',
5 `domain_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '全域id',
6 `scenic_id` bigint(20) NOT NULL DEFAULT '0' COMMENT '授权景区id,0说明为全域管理员',
7 `status` tinyint(1) NOT NULL DEFAULT '1' COMMENT '状态:1有效 0无效',
8 `create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
9 `update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
10 PRIMARY KEY (`id`),
11 UNIQUE KEY `unique_authorizer` (`authorizer_id`,`domain_id`,`scenic_id`),
12 KEY `idx_domain` (`domain_id`),
13 KEY `idx_scenic` (`scenic_id`)
14) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8mb4 COMMENT='用户-角色授权表';
role_id 为新增字段。
登录设计
因系统分saas交付和私有化交付,两种系统登录交互差异较大,针对两种交付方式设计如下。
特别注意:因系统需要支持私有化和saas两种形式部署,为解决超管问题,默认权限表(authorization)为空标记为该产品的超级管理员。
saas
saas支持用户申请入驻产品,因此流程图较为复杂。对初次扫码的用户会自动入库(平台用户user表),并依次判断是否申请过产品、产品是否完成审批、审批后查询相关的权限(创建全域或者景区自动对该用户添加管理权限);另外也支持用户扫码申请权限。
用户入驻产品后支持创建不同角色,并绑定相关人员。
saas 内部配置平台超管权限,支持用户入驻的审核。
私有化
私有化的系统为固定类型文旅通(全域or景区),不可申请入驻。
用户首次扫码后,需要由我们开发人员操作数据库进行数据初始化,包括:产品、授权表绑定用户。
流程图如下:
其他用户扫码申请授权跟 saas 保持一致,参考上文。
参考链接