java|浅谈权限管理的设计与实现

一、权限管理的意义 保证安全:避免误操作、人为破坏、数据泄露等。
数据隔离:不同的权限能看到及操作不同的数据,互不干扰。
职责明确:不同角色处理不同事务,细化职责,规范并简化流程。
二、权限管理系统的通用设计思路 某个主体(subject也就是用户) 对某个 客体(object也就是资源) 需要实施某种操作(operation),系统对这种操作的管理控制就是权限控制。
1. 权限分类

  • 操作权限
    API 权限
    菜单权限
    按钮权限
  • 数据权限
所谓操作权限就是用户是否有执行某项操作的权限,比方说是否可以审批你的考勤,具体表现形式就是用户是否可以看到某个菜单或者按钮,是否能够调用某个api(eg.对一些涉及用户信息的api做用户的登陆校验)。
所谓的数据权限就是用户是否有对某些数据的访问权限,比方说一个日志菜单,普通用户只能看到自己的操作记录,管理员就可以看到所有的用户操作行为,具体表现形式就是当用户有操作权限的时候,但不代表其对所有的数据都有查看或者修改权限。
2.访问控制权限模型
访问控制权限模型有:ACL 、DAC、MAC、RBAC、ABAC
2.1 ACL 访问控制列表 规定资源可以被哪些主体进行哪些操作
ACL, 访问控制列表,通过访问控制列表来维护用户和资源之间的映射关系。在ACL中,包含用户(User)、资源(Resource)、操作(Operation)三个元素。针对每一项资源,都配置有一个列表,记录哪些用户可以对这项资源执行哪些操作。当系统试图访问这项资源时,会检查这个列表中是否有关于当前用户的操作权限。如果有,则可以执行操作,否则会被拒绝。
ACL访问控制列表被广泛地应用于路由器和三层交换机,它可以根据设定的条件对接口上的数据包进行过滤,允许其通过或丢弃。借助于访问控制列表,可以有效地控制用户对网络的访问,从而最大程度地保障网络安全。
应用场景: 路由器、防火墙、文件系统
2.2 DAC 自主访问控制 DAC规定资源可以被哪些主体进行哪些操作, 同时,主体可以将资源、操作的权限,授予其他主体。
DAC是ACL的一种实现,强调灵活性。纯粹的ACL,权限由中心管理员统一分配,缺乏灵活性。为了加强灵活性,在ACL的基础上,DAC模型将授权的权力下放,允许拥有权限的用户,可以自主地将权限授予其他用户。
传统的Linux访问控制方式就是DAC 自主访问控制。
DAC思想:进程与其执行用户,拥有相同的权限。
例如:进程A,以root用户执行,进程A就拥有了root用户的权限。
又比如Windows的文件权限java|浅谈权限管理的设计与实现
文章图片

自主访问控制是一种比较宽松的访问控制,一个主体的访问权限具有传递性。其强调的是自主,自己来决定访问策略,但是其安全风险也来自自主。
2.3.MAC 强制访问控制 强制访问控制模型(MAC, Mandatory Access Control),是为了弥补DAC权限控制过于分散的问题而诞生的。
a. 规定资源可以被哪些类别的主体进行哪些操作
b. 规定主体可以对哪些级别的资源进行哪些操作
当一个用户执行一个操作时,需要同时满足a与b,才会被允许操作。
在MAC访问控制中,主体和资源都被赋予一定的安全级别,用户不能改变自身和资源的安全级别,只有管理员才能够确定用户的访问权限。和DAC模型不同的是,MAC是一种多级访问控制策略,它的主要特点是系统对用户和被访问资源实行强制访问控制,系统事先给用户和资源对象分配不同的安全级别属性,在实施访问控制时,系统先对用户和资源对象的安全级别属性进行比较,再决定用户能否访问该资源。
MAC的强制访问策略为每个用户、进程及文件赋于一个安全访问级别,即:
  • 最高秘密级(Top Secret,一般标记为T)
  • 秘密级(Secret,一般标记为S)
  • 机密级(Confidential,一般标记为C)
  • 无级别级(Unclassified,一般标记为U)
java|浅谈权限管理的设计与实现
文章图片

MAC非常适合机密机构或者其他等级观念强烈的行业。但对于类似商业服务系统,因为其过重强调保密性,管理不够灵活而不太适用。
2.4 RBAC 基于角色的访问控制 下述图片来自1.3 - What ANSI RBAC is
目前最为常见的权限设计模型大多都是RBAC模型, 基于角色的访问控制(Role-Based Access Control)。RBAC模型的基本思路是将访问许可权分配给一定的角色,用户通过饰演不同的角色获得角色所拥有的相应权限。
2.4.1.RBAC0 RBAC0是基于角色的访问控制的基础模型,它只包含核心的三要素,用户,角色,权限。其他的版本都是在 RBAC0 的基础上进行相应的扩展。
java|浅谈权限管理的设计与实现
文章图片

每个角色会关联一系列资源权限(多对多),而每个用户会关联一些系列角色(多对多),这样就可以很方便的控制用户能够访问的资源了
2.4.2.RBAC1 Hierarchical Role,角色继承。
引入父子角色的概念,所谓的角色继承就是子角色可继承父角色的权限,也就是RBAC1的模型。
java|浅谈权限管理的设计与实现
文章图片

2.4.3.RBAC2 Static Separation of Duties 也就是静态职责分离,用于将用户的权限限制在正常范围内,会在角色分配时应用SSD约束。
因为角色与角色,权限与权限之间可能会发生冲突,比如出纳和会计, 运动员和裁判。 一个员工是不能既是出纳,又是会计, 运行员不能既是运行员,又是裁判。
静态职责分离是指用户无法同时被赋予有冲突的角色,避免用户超出其当前职位合理的权限等级。简单地说, 就是避免两个角色间的冲突。如果员工已经有了出纳的角色,那么在给该员工赋予会计角色时,会提示角色有冲突,无法进行该操作。 也就是说在赋予角色时,会进行校验。 无论角色之间是否存在继承关系,都需要进行校验。
java|浅谈权限管理的设计与实现
文章图片

2.4.4.RBAC3 Dynamic Separation of Duties 也就是动态职责分离,强制约束是在任何时间点都可以一起使用的函数。DSD约束可用于在多步骤审批过程中实施严格控制。一般在角色激活时应用DSD约束。
java|浅谈权限管理的设计与实现
文章图片

动态职责分离,指相互冲突的角色可以同时给一个用户,但是用户在一次会话(Session)中,不能同时激活自身所拥有的互相冲突的角色,只能选择其一。
当用户登录时,或者登录成功后,会让用户选择角色,如用户选择了出纳的角色。 在运行会话期间,该用户是无法选择会计的角色进行操作的,只能先退出,再重新登录。
2.5 ABAC 基于属性的访问控制 不同于常见的将用户通过某种方式关联到权限的方式,ABAC则是通过动态计算一个或一组属性是否满足某种条件来进行授权判断。
属性通常来说分为四类:
  • 用户属性(比如用户名称)
  • 环境属性(比如当前时间)
  • 操作属性(比如读取还是写入)
  • 对象属性(又称资源属性,比如一篇文章)
ABAC的控制粒度比RBAC更细,理论上能够实现非常灵活的权限控制,几乎能满足所有类型的需求。
用户携带自身的属性值包括主体属性,资源属性,环境属性,然后向资源发送请求,授权引擎 会根据subject 所携带的属性进行判断,然后会给出拒绝或者同意的结果给用户,之后用户就可以访问资源或者拒绝访问了。
例如规则:“允许所有班主任在上课时间自由进出校门”这条规则,其中,“班主任”是用户的角色属性,“上课时间”是环境属性,“进出”是操作属性,而“校门”就是对象属性了。为了实现便捷的规则设置和规则判断执行,ABAC通常有配置文件(XML、YAML等)或DSL配合规则解析引擎使用
3. 数据权限的实现思路
数据权限是控制用户可以看到的数据,符合某条件的用户只能看到该条件下对应的数据资源。
访问控制权限是控制用户能不能访问某资源
数据权限是在用户拥有了访问控制权限后,对用户所访问的数据按照一定规则,进一步过滤出用户能看到的数据
常见于需要对某部门下的用户做数据可见性控制,如用户只能查看其本部门的数据。
数据权限主要有两个方面的作用:
(1)为了解决数据安全性问题
用户在企业的级别越高,才能看到更多的数据内容,防止大量机密数据被普通员工查看或者外泄出去。
(2)避免恶性竞争
常见于企业销售部门,销售经理辛苦积累的客户资源,不会轻易共享给其他销售经理。
常见的解决方案有:
  • 最简单 : 直接在SQL代码中加入相应的Where条件来过滤数据,适用于项目不大的场景
  • 拦截业务执行的sql,然后自动拼接数据过滤条件,但是只适合于单体应用,在分布式场景下,很难去过滤跨服务调用的数据
  • 在Controller层,通过AOP的方式,按照给定的数据规则过滤出用户的可见数据,也就是说先查询出所有的数据,然后再按照一定规则来过滤可见数据
这两篇文章 通用权限管理设计 之 数据权限 和 数据权限设计——基于EntityFramework的数据权限设计方案:一种设计思路 也提供了一种较为通用的数据权限设计思路,感兴趣的也可以去看看,大致思路就是通过配置角色的数据过滤规则来更灵活地控制用户的数据权限。
三、访问控制权限的常见解决方案
工作中我们使用的权限模型主要都是基于 RBAC, 或者在RBAC基础上进行一个扩展,常见的做法是在用户或资源侧添加额外的限制条件
1.标准场景(API、菜单、按钮) java|浅谈权限管理的设计与实现
文章图片

这是最基础的场景,也就是RBAC0模型。
一般设计成5张表:用户表, 角色表, 权限(资源)表, 用户-角色表, 角色-权限表
java|浅谈权限管理的设计与实现
文章图片

API的权限: 对用户所有的请求都需要先经过API权限的验证(可以通过切面或者过滤器实现)
1)先获取用户的角色集合A,然后根据请求的API获取拥有该API权限的集合B,如果有交集则说明有权限
2)获取用户的角色集合,之后获取其所有有权限的API集合A,判断请求的API是否在集合A中
Menu权限: 先根据用户查询出其角色集合,再获得其对应的菜单列表,组成菜单树,然后返回给前端渲染
按钮权限: 根据用户的角色可以获取其所有有权限的按钮集合B, 在渲染页面时根据按钮是否在集合B中决定按钮是显示还是隐藏
2.引入组 为了更好地管理用户,对用户进行分组归类,可以引入组的概念。
在实际情况中,我们知道,组也可以具有自己的角色信息、权限信息。比方说QQ用户群,一个群可以有多个用户,一个用户也可以加入多个群。每个群具有自己的权限信息。例如查看群共享。QQ群也可以具有自己的角色信息,例如普通群、高级群等。
java|浅谈权限管理的设计与实现
文章图片

引入组的概念之后,用户拥有的角色,即为用户自身所拥有的角色集合与用户所属组拥有的角色集合的并集 ,这样想要给某一用户组的所有用户都加上某角色的权限,只需要给组赋予相应角色就可以了
3. 角色继承 为了提高授权的便捷性,我们还可以提供角色复制、角色继承的功能,即角色可以被拷贝、继承,也就是前面提到的RBAC1的模型。
拷贝的角色可以拥有与被拷贝角色相同的权限;而对于角色继承,子角色可继承父角色的权限(跟java中的继承类似)。
java|浅谈权限管理的设计与实现
文章图片

4. 引入功能模块 前面的资源分为API, 菜单, 按钮三类;但是很多资源之前都是有关联性的,可以将关联的资源聚合成功能模块,更方便我们对资源进行分配
java|浅谈权限管理的设计与实现
文章图片

我们可以将菜单也视为一种功能模块,也可以将菜单单独授权
5. 多应用授权中心 如果有多个服务都需要设计权限系统,那么可以权限服务独立出来,让其为多个应用提供权限管理。
每个需要进行管理的服务都可视为一个应用(Application), 每个应用下可以有各自的用户、角色、资源,同时一个用户也可属于多个应用。
java|浅谈权限管理的设计与实现
文章图片

权限服务不单单可以维护其他应用的权限,还可以维护权限服务自身的权限。
【java|浅谈权限管理的设计与实现】参考资料:
1.3 - What ANSI RBAC is
权限系统设计模型分析(DAC,MAC,RBAC,ABAC)

    推荐阅读