前面已经写了一篇基于RBAC权限模型的理解设计,我们希望权限系统满足以下的特性:
1. 数据跟随人和部门,也就是谁产生的数据归谁,哪个部门产生的数据就归哪个部门,也就是数据除了关联用户ID,还应该关联部门ID;
2. 一个人可以属于多个部门,在不同的部门可以拥有不同的角色,例如在这个部门是管理员角色,但是在另一个部门却是普通用户;
3. 角色可以灵活定义不同的功能权限和数据权限。
权限模型算是比较清晰了,但是深入去思考其中的逻辑,发现还是有不少的坑需要填的。
需要给用户设置独立的权限
系统有时候需要给某个用户设置独立的权限,这种情况用前面的逻辑其实是可以解决的,只需要先创建一个特别的角色,给它赋予权限,然后和用户关联起来就可以了。但是这样操作会比较复杂,关键是可以会产生很多只会被某个用户用到的角色,对角色管理和选择造成困难。
当然也可以在用户表直接关联权限项,但是这样权限的查询实现就复杂了,而且可能还得增加一个用户与权限项的关联表,这个系统复杂度不可取。
这两个方案,第一个只是操作复杂一点,但是基于这个一个特殊情况的假,反而是可以接受的,只是它不完美。是否可以结合这两个方案的优势呢?
自然是可以的,在角色里增加一种虚拟角色的类型,这种角色仅用于绑定用户绑定特定权限,不需要在角色管理中进行管理,操作上不增加复杂性,实现上也不增加太多复杂性,查询功能则和原来完全一样。
数据的部门属性
看起来只要给数据绑定一个部门属性即可,但是因为部门本身的可变性,导致这里是主要需要权衡和设计的地方。
部门数据查询通常有三种类型:
1. 查询某个部门的数据;
2. 查询某个部门及其下属部门的数据;
3. 查询指定某些部门的数据。
类型1和3本质上是同一个问题,一个in就解决,而类型2则要重点考虑。实现方式可以有两种:
1. 转化为类型3来处理,某个部门及其下属部门其实也是一堆部门ID;
2. 数据和部门路径关联,所谓部门路径就是从顶级部门到当前部门的路径,这样查询的时候是最简单的,使用前缀索引就能匹配到。但是这有一个致命的缺陷,但是如果部门的上下级关系改变的时候需要将所有业务表对应的部门属性进行更新,这个操作几乎无法接受。虽然部门关系变更的情况很少,但是很难保证不会发生,一旦发生可能会出现大规模锁表的情况,实现复杂而且可能会影响正常的业务。
所以,我们只能选择第一种方式,这时数据表建索引也简单,不过这也有不太优雅的地方。如果下级部门非常多,那这个查询语句就很大,对查询性能应该说会产生影响。(从这点上看,有些会在部门的树结构上,分拆出一个域的概念也是有道理的,不过这个域也会增加数据表的复杂度,因为要多绑定一个域)
角色表中对部门数据权限的定义
前面讲了数据表的部门属性,而角色表中的权限也有对应的定义,部门数据权限的定义方式有:
1. 本部门数据
2. 本部门及下级部门数据
3. 指定部门数据
和前面一样,1和3其实是一样的,只需要一个角色与权限的关联表即可,但是对于2的实现就要做取舍了。因为前面查询已经使用了转换成3的方式进行处理,这里也应该采取同样的方式进行处理。不过这个选择在角色表的成本却大很多,因为当部门的上下级关系变更(这应该是极少数的情况,不实现问题也不大)时,需要更新所有对应的上下级关系。
部门删除
删除部门也是一个重要需要决策的问题。以下几点:
1. 如果部门存在正常的下级部门,不应该被删除;
2. 部门被删除了,其上级部门应该还能查询该部门的数据,如果有权限;
3. 前期也不需要考虑将删除部门的数据合并到其他部门,需要更新的地方太多;
用户权限系统是系统安全的重要组成部分,想做好那要考虑的问题还不少。
--------
0930于车上