前段时间分别用vue和react写了两个后台管理系统的模板vue-quasar-admin和3YAdmin。两个项目中都实现了基于RBAC的权限控制。由于本职工做是后端开发,比较清楚权限控制一个管理系统应该必须具有的核心功能,并且是能够作到通用的。打算写写关于管理系统先后端分离方面的文章,也是作一个知识的总结,其中会涉及到vue,react,node,.net core等方面的知识。html
权限有时候也能够称为动做或者功能。好比“添加文章”,既能够认为它是一个动做,也能够认为它是一个功能。对象也能够称为资源。vue
ACL是最先也是最基本的一种访问控制机制,它是用来描述用户和权限之间关系的数据列表。它的原理很是简单:每一项资源,都配有一个列表,这个列表记录的就是哪些用户能够对这项资源执行CRUD等操做。当试图访问这项资源时,会首先检查这个列表中是否有关于当前用户的访问权限,从而肯定当前用户能否执行相应的操做。node
例如一个文件对象的 ACL 为 Alice: read,write; Bob: read,这表明 Alice 对该文件既能读又能写,而 Bob 只能读取。react
因为ACL的简单性,使得它几乎不须要任何基础设施就能够完成访问控制。但同时它的缺点也是很明显的,因为须要维护大量的访问权限列表,ACL在性能上有明显的缺陷。另外,对于拥有大量用户与众多资源的应用,管理访问控制列表自己就变成很是繁重的工做。git
最开始的ACL定义中,用户直接和权限挂钩,数据存储的是用户与权限的关联关系。若是两个用户的权限是同样的,那么就须要分别存储这两个用户与权限的关联关系,也是上面所提到的ACL的缺陷。为了解决这些问题,便有了对ACL设计的改进,相同权限的用户放到同一个分组里,分组与权限挂钩,再也不是用户直接与权限挂钩。以及后来出现的RBAC(基于角色的访问控制),角色与分组也是差很少的概念,角色直接与权限挂钩,用户再与角色进行关联。github
因此,如今通常说ACL,再也不是用户直接和权限挂钩的一种权限控制模型,把它看作一个单纯的访问控制列表便可。列表里维护的多是用户与权限的关系,也能够是用户组与权限的关系,也能够是角色与权限的关系,甚至是部门,职位等等于权限的关系。json
ACL是权限体系中的业务规则。RBAC等权限模型要用到ACL才能工做,ACL服务于RBAC等权限模型,其它权限控制体系里的权限规则也叫ACL。后端
系统会识别用户,而后根据被操做对象(Subject)的权限控制列表(ACL: Access Control List)或者权限控制矩阵(ACL: Access Control Matrix)的信息来决定用户的是否能对其进行哪些操做,例如读取或修改。
而拥有对象权限的用户,又能够将该对象的权限分配给其余用户,因此称之为“自主(Discretionary)”控制。缓存
由于用户能自主地将本身拥有的权限授予其余用户,因此DAC模型能够任意传递权限,用户能间接得到本不具备的访问权限,所以DAC模型的安全性较低,不能给系统充分的数据保护。安全
DAC能够直接使用ACL的物理模型,区别在于,DAC模型中用户能够将本身具有的权限分配给其它用户(程序里的操做就是根据用户ID筛选出权限列表,根据列表为要分配权限的用户构造出新的权限列表并保存)
DAC是传统的UNIX访问控制模型,也是Windows文件系统的访问控制模型。
Windows的文件访问权限的设置中,除了用户,还有组。这个组与后面要说到的RABC模型的角色有什么区别呢?
https://stackoverflow.com/questions/7770728/group-vs-role-any-real-difference
我认为不必去划分的太清楚,无论是组仍是角色,都是为了更好的管理和分配权限在最原始的ACL模型上作的改进。若是有须要,甚至能够把权限分配到部门,职位上。
MAC是为了弥补DAC权限控制过于分散的问题而诞生的。在MAC的设计中,每个对象都有一些权限标识,每一个用户一样也会有一些权限标识,而用户可否对该对象进行操做取决于双方的权限标识的关系,这个限制判断一般是由系统硬性限制的。访问时,系统先对用户的访问许可级别和资源对象的密级进行比较,再决定用户是否能够访问资源对象。用户不能改变自身和资源对象的安全级别,只有系统管理员或管理程序才能 控制资源对象和用户的级别。好比在影视做品中咱们常常能看到特工在查询机密文件时,屏幕提示须要“没法访问,须要一级安全许可”,这个例子中,文件上就有“一级安全许可”的权限标识,而用户并不具备。
MAC很是适合机密机构或者其余等级观念强烈的行业,但对于相似商业服务系统,则由于不够灵活而不能适用。
MAC能够继续使用DAC的模型,可是要对用户进行等级划分,好比一级,二级,三级。。。,对对象资源也要作划分,好比机密,秘密和最高机密。用户访问的资源的时候,根据用户等级与资源访问级别来作判断,好比一级用户只能访问机密文件,若是访问的是最高机密文件,系统就会拒绝。这一系列规则是优先于DAC的,若是MAC与DAC混用,要先校验MAC再校验DAC。
ACL的访问控制机制中,直接维护的是用户与功能的关系,这一系列的关系就是一个权限列表。当不少的用户具备相同功能权限的时候,就要进行繁琐的关联操做。RBAC就是在用户与权限之间引入了角色的概念。用户与角色之间作关联,权限列表维护的是角色与功能的关系。
RBAC是目前使用最广泛的权限控制模型。当某些用户具有相同的权限的时候,只须要为这些用户建一个角色,把相应的功能关联到这个角色上,生成角色的权限列表。当有新的用户须要相同权限的时候,把用户关联到这个角色上便可。而当用检查或校验用户的操做权限的时候,查询用户所属角色的权限列表便可。
固然,RBAC也不是完美的,好比想要为某个用户单独设置某个功能权限,可能须要为这个功能权限单首创建一个角色,而后把特定的用户关联到这个角色上。当想要移除某个用户的特定功能权限的时候,可能须要从新设置角色的功能权限,把特定功能权限从当前角色中移除,创建新的角色并关联特定的功能权限,而后再把新角色与相关的用户作关联(也能够直接在特定功能的程序里校验操做用户)
这里说一个比较常见的RBAC的错误的用法:那就是直接使用角色作权限判断。好比只有角色A才能作文章的删除操做。
function delPost(postId){ if(!isRole('A')){ return false; } }
若是需求该为角色B也能够删除文章。那就必须修改代码
function delPost(postId){ if(!isRole('A')&&!isRole('B')){ return false; } }
正确的作法应该是添加"删除文章"这个功能,把这个功能关联到相应的角色上。判断的时候是根据功能去判断而不是角色。
function delPost(postId){ if(!hasPermission('POST_DEL')){ return false; } }
针对“只有角色A才能作文章的删除操做”这一需求,把这个删除功能关联到角色A上,而后把须要这个操做权限的用户加入到角色A中便可。当别的角色也须要这个操做权限,把功能关联到对应角色上便可,不须要再修改代码。
在RBAC的核心基础上,还能够作相应的扩展,好比角色继承,角色分组之类的,这些扩展都是为了在必定程度简化权限管理工做。
RBAC虽然是目前最广泛的权限控制模型。可是某些状况下,RBAC是没法知足而且也实现不了的。好比业务员1和业务员2都属于业务员角色,都有查看客户订单的权限。当有一个需求,要求业务员1只能查看北京地区的客户的订单,业务员2只能查看上海的客户的订单。这单单使用RBAC是没法实现。借助RBAC,可行的作法是,分地区建立角色,而后程序中根据角色作数据的过滤,这种作法缺点以前也提到过,需求变动的时候可能须要每次都修改代码。
上面业务员查看订单的例子,地区是订单的一个属性,需求就是针对这个地区属性来作订单的查询范围的权限控制。这种权限控制方式就是ABAC(Attribute-Based Access Control)(基于属性的权限控制),也被一些人称为是权限系统设计的将来。
不一样于常见的将用户经过某种方式关联到权限的方式,ABAC则是经过动态计算一个或一组属性是否知足某种条件来进行受权判断的(能够编写简单的逻辑)。属性一般来讲分为四类:用户属性(如用户年龄),环境属性(如当前时间),操做属性(如读取)和对象属性(如一篇文章,又称资源属性),因此理论上可以实现很是灵活的权限控制,几乎能知足全部类型的需求。
例如规则:“容许全部班主任在上课时间自由进出校门”这条规则,其中,“班主任”是用户的角色属性,“上课时间”是环境属性,“进出”是操做属性,而“校门”就是对象属性了。
ABAC很是的灵活,可是实现也是很是的难。这其中涉及到逻辑的动态执行,数据动态过滤等,更加具体就是动态拼接SQL语句(使用ORM的话就是动态组装对应ORM的查询语句)。
感兴趣的能够在Github上搜索ABAC,看看不一样语言是否已经有现成的解决方案。下面说说我学习到的一种实现方式:
仍是业务员查看订单的例子,在RBAC的基础上,扩展一个实体规则,订单就是实体,也就是针对订单设置一系列的规则。规则存储格式能够是json也能够是xml,甚至是Sql语句,能解析便可。好比北京地区这个规则:
{ "regionId":1 }
上海地区:
{ "regionId":3 }
regionId
就是系统里对应区域的Id,也是订单或订单相关表的某个字段。
保存这个规则的时候,规则内容(就是上面的json),规则实体(也就是订单,代表这个规则是针对订单的)是必须的。也能够加上这个规则是适用增删改查中的一种或多种。
建立好实体的规则,将规则与角色作关联,也就是将北京地区的规则关联到北京地区角色上,上海地区的规则关联到上海地区角色上。
后端作权限校验的时候,仍是先按RBAC模型的控制方式进行校验(是否具有订单查看权限),而后根据当前操做对象(也就是实体),取出用户所属角色关联的对应实体的规则。而后解析规则,动态拼接Sql或者ORM语句。
没作地区限制(或没配置规则)的时候,Sql多是
select userId,orderNo,createdDate from T_Order
配置了规则,解析拼接后可能就是
select userId,orderNo,createdDate from T_Order where regionId=1
这里是针对地区这个属性实现了动态的权限控制。实际开发过程当中,要控制的东西是很是多了,查看字段的控制,数据范围的控制。要知足这些复杂的控制,须要制定一套完整的规则,以及针对规则编写相应的解析程序。好比根据配置的规则,最后解析出来多是各类Sql语句:<,>,=,like,in,not in等等。
能够看出,要真正的落地实现ABAC是多么的复杂。每次都要解析规则,对程序的性能也形成的影响,就算使用缓存,命中的几率也是很是的小,由于不少因素都是动态的。
因此,若是须要根据属性作权限判断的场景不是不少的话,仍是建议使用RBAC,而后程序中作判断比较省事省力。
ACL早期定义中是一种权限控制机制,这种机制直接维护的是用户与功能的关系,功能就是针对对象定义的一些操做,好比增删改查的等。用户与功能的关系列表也称为权限列表或访问控制列表,如今说ACL,通常就是指这个权限列表或访问控制列表,可是里面维护的关系不必定是用户与功能的关系,在RBAC中维护的就是角色与功能的关系。
RBAC在ACL的基础上加入了角色的概念,权限列表或访问控制列表里维护的再也不是用户与功能的关系,而是角色与功能的关系。ACL能够和RBAC混着用,既能够在角色上设置权限,也能够直接给用户设置权限,更加灵活。借助角色的思想,能够在用户组,组织,职位等等上设置权限,以便更好的作好权限管理,也就是将权限设置从单一个体转移到某一类组合上。
ABAC很是的灵活,也很是的难实现。