在项目的实际开发中,我们不仅需要控制用户可以访问哪些资源,还需要控制用户只能访问资源中的某部分数据。为了控制用户可以访问哪些资源,我们有一个非常成熟的权限管理模型,叫做RBAC,但是使用RBAC模型仅仅控制用户只能访问某些资源(也就是我们常说的数据权限)是不够的。在本文中,我们尝试使用基于RBAC模型的数据权限管理控制。首先让我们看一下RBAC模型。RBAC模型RBAC是Role-BasedAccessControl的英文缩写,意思是基于角色的访问控制。RBAC会预先在系统中定义不同的角色,不同的角色有不同的权限。角色实际上是一组权限。系统的所有用户都会被赋予不同的角色,一个用户可能有多个角色。使用RBAC可以大大简化权限的管理。RBAC模型还可以细分为RBAC0、RBAC1、RBAC2、RBAC3。这里我们不讨论它们之间的区别。有兴趣的同学可以自己研究。我们主要关注常见的RBAC0模型。下图是一个经典的RBAC0模型的数据库设计。在RBAC模型下,系统只验证用户A是否属于角色RoleX,不判断用户A是否可以访问只属于用户B的数据DataB,我们称这种问题为“横向权限管理问题”。数据权限列表数据权限主要是通过数据权限控制行数据,让不同的人有不同的查看数据规则;要实现数据权限,最重要的是抽象数据规则。数据规则,比如我们系统中的商机数据,需要从以下几个维度来控制数据的访问权限。销售人员只能查看自己的数据;每个区域的销售经理只能查看本区域的数据(安徽区域的销售经理可以查看安徽区域的商机数据),BG领导同理,只能查看所在地区BG的商机数据;财务人员只能看到金额小于10000的数据。以上维度为数据规则。这样,我们也明确了数据规则的几个关键要素,分别是规则字段、规则表达式和规则值。以上三种场景对应的规则如下:规则字段:创建者,规则表达式:=,规则值:当前注册人规则字段:地区,规则表达式:=,规则值:安徽地区规则字段:销售额,规则表达式:<,规则值:10000规则字段配置说明:条件表达式:大于/大于等于/小于/小于/等于/等于/包含/模糊/不等于规则值:指定一个值(固定值/系统上下文变量)将资源和用户与数据规则关联起来是不够的,我们还需要将数据规则与资源和用户绑定。数据规则和资源的绑定非常简单。我们只需要创建一个中间表,如下图所示:这样就可以将资源和数据规则关联起来。在应用设计中,我们需要一个单独的数据规则管理功能,方便我们录入数据规则,然后在资源管理页面(如商机列表),我们可以选择内置的数据规则进行绑定资源和规则。那么如何让不同的用户拥有不同的数据规则呢?在RBAC模型中,用户通过授予不同的角色来管理资源。同样,我们可以在授予权限的时候将角色和数据规则关联起来,这样不同的用户在系统中就有不同的数据规则。.有点啰嗦,还是照上面的例子来吧。销售人员、区域销售经理、财务人员属于不同的角色。他们都拥有商机列表的资源权限,但是我们可以在将这些角色绑定到商机列表的资源权限时,查看对应的数据规则(上面已经实现了资源与资源数据规则的绑定)。体现在数据库设计上,我们可以在角色资源对应表Role_Permission中增加一个字段来存储关联的数据规则。如果有多个数据规则,可以用分隔符分隔。最终,RBAC模型演变为如下模型:根据上面的设计,我们需要区分每个区域管理的数据权限,然后我们需要建立不同的区域角色,比如安徽区域的销售经理和上海区域的销售经理,然后分配给他们选择角色对应的数据规则。这类似于RBAC1中角色继承的概念。这样我们就基本实现了RBAC和数据规则的绑定,但是在系统中如何实现还有一个问题。这里我们将使用著名的AOP来实现它。本文只讲原理不讲实现,所以只顺便提一下实现方案。自定义一个数据权限注解,比如PermissionData,在对应的资源请求方法上添加自定义注解,比如商机列表@PermissionData使用AOP抓取用户对应角色的所有数据规则并进行SQL拼接,最终实现它在SQL级别进行数据过滤。继续优化。在上面的设计中,我们通过为不同的角色绑定不同的数据规则来实现数据权限,但是考虑如下场景:一个角色需要看到的数据范围是“所属区域是安徽地区,业务部门是业务消费业务部机会数据”,在这个场景中,根据我们之前的设计,我们需要建立两条数据规则:分区域=安徽大区业务部=消费业务部然后创建2个不同的角色,授予不同的数据规则分别地。如果这样的场景很多,很容易造成角色爆炸。所以这里我们提炼出数据规则组的概念。一个数据规则组有多个数据规则,数据规则之间用AND连接,放一张应用设计图:体现在数据库设计中,变成如下:总结通过以上8张表的设计,我们有实现了RBAC模型和数据权限的结合,当然还有进一步优化的空间。比如我们可以把这里的规则字段和规则值提取出对应的字典表,让数据规则表关联这些字典字段,这样在应用层配置数据规则时,管理员就不需要手动填写它们,但来自字典项目。选择以减少数据规则配置错误的概率。数据权限是一个实现起来比较复杂的功能。这里我们选择在RBAC模型的基础上进行扩展。如果你有更好的解决方案,欢迎留言告诉我。
