运维咖啡吧

享受技术带来的乐趣,体验生活给予的感动

权限管理系统设计

上周分别分享了任务系统的两个主要功能:手动审批并行任务,今天再来聊下任务系统的权限设计,实际上关于权限系统的设计并不只适用于任务系统,作为PAAS平台基础服务后续会贯穿所有的上层SAAS应用中

之前在写Probius的介绍文章时,大概提过Probius的权限设计,主要是RBAC+单独对象授权的方式,而本次任务系统的权限设计除了延续之前的授权方式外,还新增了非常重要的资源隔离,接下来简单的说下这三种授权方式的区别跟实现

默认权限

熟悉Django的朋友都知道,Django是有自带的权限系统的,如果把Django里的Group看作Role且抛弃用户单独授权的话,那大概的授权流程就变成了将用户加入组,给组授予对应模块操作的权限,那用户就有了相应模块的权限,这个授权方式就跟常见的RBAC权限模型非常相似了

举例来说,假如用户A具有任务管理员角色,任务管理员角色拥有任务修改和任务执行权限,那用户A就拥有了任务修改和任务执行的权限,清晰易懂很好理解,用起来也很方便,但Django的默认权限控制粒度比较粗,控制的最小粒度是表,也就是说你如果给了任务修改的权限,那么用户将能够修改所有的任务,这对于不同人员维护不同项目的团队是无法很好授权的

关于Django的默认权限这篇文章有详细的介绍:Django默认权限机制介绍及实践,这里不再赘述了

对象授权

针对Django默认权限控制粒度粗的问题,我在Probius中引入了对象权限,对象权限的最小控制粒度是表里的单条数据,既然想把不同的任务分配给不同的用户,那通过对象授权就能很好的解决

默认权限在对象授权的加持下能解决授权粒度太粗的问题,如果仅仅是需要任务执行这个功能需要单独授权的话还好,但是当需要授权的功能有N多个的时候就会非常崩溃了,每一个权限每一个资源都需要单独授权,管理起来非常繁琐,例如子任务的增删改查、模板的增删改查、执行用户的增删改查都需要单独授权,那再采用对象授权的方式就不敢想象了

关于Django的对象授权这篇文章有详细的介绍:Django Object Permission之Django-guardian使用详解,这里也不赘述了

资源隔离

默认权限的授权粒度太粗,而对象授权的授权粒度又太细,资源隔离就是在两者之间取一个平衡。这里所讲的资源隔离与通常所说的多租户以及云上的资源组概念类似,就是所有资源先按照业务或是项目进行隔离,我们是按项目维度进行隔离,用户所属项目,项目拥有相应的资源,那用户也就继承了项目的资源,这里的资源指的是数据表里的每一条数据,例如任务表下的每一条数据都算一个资源

举例来说,用户A隶属于OpsCoffee项目,OpsCoffee项目拥有任务ABCDE,那用户也就有了任务ABCDE的权限,至于是何种权限,修改还是删除还是执行那就配合默认权限来实现了。这种方式需要给所有的资源都先标记项目,我们默认项目下的成员对项目内的资源拥有权限,这样的话用户只对自己的项目资源有权限,资源粒度范围大大缩小了,同时也省去了每个资源单独授权的烦恼

实现逻辑

资源隔离的实现逻辑比较简单,首先在所有需要资源隔离的表里添加project字段以标识资源隶属于哪个项目,后续所有的逻辑都会基于这个项目标识去处理

当用户进入页面时,先获取用户所有项目列表,然后判断浏览器Cookie里是否有project,如果有则默认选中project,如果没有则取第一个project并写入Cookie

当点击切换项目时会同时修改掉Cookie里的project值,然后重新加载页面,以保证当前页面的数据跟所选择的项目一致,对于页面数据的增删改查都默认传递project参数,后端会根据传入的project参数判断用户是否有权限,同时添加数据时也会默认加上传递的project

需要注意的是,传递给后端的project不要去Cookie中获取,不然会出现多个浏览器窗口打开不同项目造成的数据错乱问题,我是直接从页面左上角的Select选择框获取当前项目传递给后端的

权限终章

最终的权限管理方案是整体上采用RBAC+资源隔离的方式,仅对小部分非常敏感的数据再通过对象授权的方式做管控,这样在兼顾便捷性的同时也能做到很好的资源管控

RBAC:用户赋予角色,角色赋予模块操作的权限,则用户拥有对应模块的权限,资源隔离:用户隶属项目,项目拥有资源的权限,则用户继承对应资源的权限,两者结合的最终结果就是用户仅对自己所在项目的资源拥有部分模块操作的权限