本权限模型是基于RBAC1模型。RBAC1的特点是Role可以继承,本权限模型仅使用了RBAC1的“受限继承关系”,即Role的继承关系是一个树结构,不允许多继承。
1. IUser
IUser是用户。这里的用户是指广义上的用户,不但包括员工,也包括用户组、职位等,它代表角色拥有者。
2. IRoleIRole是角色。角色的作用是隔离用户和资源,避免资源直接耦合用户。
2.1. IAdminRole
IAdminRole是有管理权限的角色。这类角色可以新建子角色,并且可以在本身的权限范围内给子角色分配资源。此类角色一般是分配给部门主管使用。
2.2. IGeneralRole
IGeneralRole是普通角色。它只能行使被分配后的权限,适合分配给普通员工。
3. IResource资源是权限管理的重点。在此把资源分为功能资源和数据资源。
为什么要分功能资源和数据资源?
功能资源和数据资源两者的含义相差太大,没办法综合起来。功能资源是类型级别(the type of resource),而数据资源是实例级别(the instance of resource)。
功能资源属于粗粒度资源,数据资源属于细粒度资源。
3.1. IFunctionResource
IFunctionResource表示功能资源。
功能资源是指那些在表示层以功能性接口表达的,通常能够与客户进行交互的资源。
与客户的交互有时候是直接的:某个按钮处于禁用状态;某一个文本框只读;表格中某一列不可见等。
有时候交互是间接的:当客户填写了某一单价,系统验证超过最高价,那么提示用户重录。
功能资源是针对类型(the type of resource)的,并不区分单个实例(the instance of resource)。比如销售订单的“审核”功能,就是针对销售订单模块(所有的销售订单),并不管其中某一张销售订单能否审核。
3.1.1. 功能资源与UI验证
功能资源可以与UI验证结合起来,比如验证某一字段的最大长度、最小值等。
3.1.2. 功能权限的实现
功能权限可以看作业务模型的映像,属性资源可以映像为文本框、RadioButton、Checkbox、Combox等,方法资源可以映像为按钮等。
功能权限因为要与用户交互,所以它应该能控制UI的渲染,比如按钮的禁用、文本框的只读等。
3.2. IDataResource
IDataResource表示数据资源。
数据资源的特点是结构稳定,但内容无限扩展的资源。例如每一张销售订单、客户的每一种类型都是属于数据资源。
数据资源是针对实例(the instance of resource)的。
4. 资源的粒度
从模型设计上看,功能资源和数据资源分别代表了粗粒度的权限管理和细粒度的权限管理。
功能权限的设计和实现已经非常成熟稳定,没有什么问题。但数据资源的设计究竟需要“细”到什么程度,以及如何灵巧地(低侵入性、过滤接口简洁)实现数据权限需要详细规划。
4.1. 细粒度数据资源带来的问题
1. 权限数据太庞大。
每一笔业务数据都要给角色(可能是多个角色)分配权限,其数据量会以N倍(记录数*角色数)的速度增长。
数据量庞大还会使得分配权限的工作量太大,导致无法人工完成授权。即使人工能够完成,也会带来滞后问题(新增的单据无法立即被授权使用)。
所以细粒度的Resource权限需要自动授权来完成权限管理。但自动授权增加了系统的复杂度,而且太依赖程序员手工调自动授权的API。
2. 权限数据与业务数据要同步。
当分配了数据权限之后,如果业务数据被删除了(业务数据是易变的),那么权限数据也要同步更新,这非常麻烦,如果不是三层,根本没办法统一处理,只能依靠程序员不会忘记调用同步权限的API。
4.2. 细粒度的数据资源设计
就目前看来,数据资源的粒度至少可以划分为两个级别:Catalog级别、Detail级别。
4.2.1. Catalog级别
Catalog级别是指那些目录式或者类型归纳式的数据资源,例如产品目录、客户类型等。
Catalog级别的数据资源的特点是,虽然它属于细粒度的实例级别的资源,但它的实例是有限的、相对稳定的。
l Catalog级别的优点
Catalog级别的资源能满足“粗略”的数据权限管理,又不会让数据资源增长得太厉害。
l Catalog级别的缺点
Catalog级别的资源无法满足“最小实例”级别的数据权限管理。而且如果数据资源是无法分类的,那么也不能使用Catalog级别的数据权限管理。
4.2.2. Detail级别
Detail级别是“最小实例”的数据资源,例如一份合同、一张销售订单。Detail级别的数据资源的特点是:资源实例的数量无限增长。
l Detail级别的优点
数据权限非常精确,能够管理到最细致的数据记录。
l Detail级别的缺点
需要与业务数据同步;
权限数据增长太快、数据量过于庞大,不便于权限管理。
4.2.3. 具体设计
本模型中没有使用Detail级别的数据资源,我尽量把数据分类别,比如单据按部门分类,客户按地区分类,货品按类型分类。这些类别不会经常改变,最主要的是它们不会无限膨胀。
5. 权限指定到人权限指定到人的情况,通常发生在Detail级别的数据资源权限管理上。
比如这样的业务需求:一份销售合同(它属于Detail级别的数据资源)只能被它的创建者(User)删除,与创建者同小组(UserGroup)的用户可以修改,同部门(OU)的用户能够浏览。
这既属于权限管理问题,也属于业务逻辑问题。作为权限问题时,就是把权限分配给个人;作为业务逻辑问题时,它属于专属业务,与其它的业务不共享逻辑。
“权限指定到人”本质上属于业务逻辑问题,因为它的权限管理不具有通用性,不能通过统一的规则对权限进行判断。
5.1. 解决方案
如果一定要管理权限分配给个人的情况,那么有以下三种解决方案。
最终使用了第二种方案,虽然这种方案不够完美,但它毕竟符合RBAC的模型定义,而且也容易理解。
5.1.1. User直接关联Resource
这种模式违背了RBAC模型的定义,Role相当于被废弃了。这种模式相当于ACL模式。
5.1.2. 每个User一个专用Role
上面的模型中,User1和User都有专用的Role(Role1和Role2)。
这种模式在表面上符合RBAC规范,但实际上脱离了RBAC的精神。这种模式导致每个User都有一个专用的Role(User与Role一对一),这个Role不能被别的User使用,这相当于Resource直接绑定到了User。
5.1.3. 每个Resource一个专用Role
上面的模型中,Resource1和Resource2都有专用的Role(Role1和Role2)。
这种模式是上一种模式的逆向解决方式。这种模式避免了User与Role的一对一,又避免了Resource与User直接关联。
这种模式的缺点是,因为Role是Resource专用的,别的Resource不能使用这个Role,所以Role的生命周期和状态必须与Resource同步:当Resource删除时Role也必须删除,当Resource停用时,Role也必须停用。这会带来维护上的困难。