建立一个小型权限管理模型
公司的产品最近开始向 CRM 产品转型,组织上决定设计一个新的业务权限描述模型。
业务权限描述模型是为了解决「是否允许谁对什么做什么」而设计的存储结构。首先,在满足范式的前提下很容易设计出一个最小的权限描述模型
最小模型支持存取每个用户对 object
的操作权限(通过添加和删除 can_handle_object
记录)满足了权限管理的基本需求。
第二步,管理更多实体。假设这是一家连锁超市仓储管理系统的数据库,那么 object
可能是 product
、depot
或者 store
。比如在语境「“修改用户权限”的权限」里 object
是 user
实体。
比较正确的姿势是采用类似“继承”的做法
p_node
意思是 permission node。考虑实际语义的话,称为 pctl_node
会更好。
外键 p_node_id
相当于面向对象语言实现上的基类指针,因此可以通过 can_handle_object
查询任何含有 p_node_id
的实体的权限。PostgreSQL 的 INHERITS 语法也是相似的原理。
新模型可以描述不同实体的权限,权限的管理却依旧非常困难 —— 假设 user
、permission
和 p_node
数量分别为 、、 则
- 添加一个
user
需要考虑 个权限关系 - 添加一个
permission
需要考虑 个权限关系 - 添加一个
p_node
需要考虑 个权限关系
不难看出,虽然可以从最小的粒度进行最精细的权限管理,但是无论就性能还是可用性而言目前的设计都是不可接受的。
改进方法是增加层级,比如引入 permission_group
实体
把 个权限表示为 个 permission_group
则原本 的记录规模就能缩减到 。使用类似的思路创建 user_group
实体也可以减小 对应的规模。
在更复杂的需求中,可能发生几个 permission_group
包含相同 permission
或者类似的情况。设计权限描述模型的时候就需要使用 m:n 来表示“组”和实体的关系。
最后,当然不会忘了给 p_node
增加层级,p_node
的数量可比前两者多的多的多,因此这是个设计时必须考虑的方案。有了先前的经验很容易想到添加一个 p_node_group
,但更高效的做法是给 p_node
添加一个到自己的 1:n 关系
新模型相当于同时定义了
p_node
p_node_group
group_of_p_node_group
group_of_group_of_p_node_group
- …
那么 p_node
可以有任意多层!每个 p_node
都可以关联到一个父节点,形成一个树状结构。和某个节点建立关联就可以表示用户到该节点和所有子节点的权限。
这个结构需要递归查询,得到每一级 p_node_id
之后连接 can_handle_object
及其相关表就能得到权限结果。
综上所述,权限描述是一个对 m:n:k 关系(谁/对什么/做什么)的建模问题,不同的权限管理需求决定不同的组织形式:
- 不分层,如
user
- 目录式(1:n)
- 单层,如
permission
- 多层,如
p_node
- 单层,如
- 标签式(m:n)
- 单层,如 Unix 用户/组
- 多层
除了权限描述模型,相同的模式也适用建模优惠券业务和其他多对多对多关系的建模。