关于权限控制:PingCode-Wiki-权限设计之ACL

8次阅读

共计 4755 个字符,预计需要花费 12 分钟才能阅读完成。

2021 年 Wiki 退出了很多强硬的个性,其中包含协同编辑、页面权限、表情符号 等,这些性能给用户带来了更好的体验。作为 Wiki 使用者兼开发者,今日来聊聊年初上线的 页面权限,同时总结一下开发阶段波及到的技术、遇到的问题以及解决方案,对于权限自己之前曾经写过一篇 Worktile 权限的文章了,Worktile 权限着重讲了 RBAC(基于角色的权限管制计划)的设计与实现,本文基于 Wiki 页面权限抉择的另一个支流权限设计的计划:ACL

本文大抵分为三局部:

  1. ACL 介绍
  2. 介绍咱们的权限以及为什么抉择它
  3. 设计实现

一、ACL 介绍

1. 什么是 ACL?

ACL:Access Control List,权限管制列表,是对文件以及目录的权限管制计划。赫赫有名的 Linux 权限零碎,它就是 ACL 的典型案例,自己在开发过程中也受到了 Linux 权限设计的一些启发。

2. ACL 的应用场景

应用场景也能够换个问法:为什么要应用 ACL?对于这个问题咱们还以 Linux 作为案例:Linux 自身只提供了 Owner(所有者)、Group(用户组)、Others(其余成员),也就是说其余成员或用户组是无奈指定更细粒度的权限。

为了更好的解释,咱们来举个简略的例子(场景):

有 4 个成员有 A、B、C、D,其中 A、B、C 是开发组 G 的成员,A 成员创立了一个代码仓库并把团队开发的代码搁置到该目录中,其中这些代码次要是对于 G 组的,与其余成员无关,所以 A 把文件目录设置了权限,权限是组内可读可写,其他人没有任何权限。

当初来剖析一下各个角色,A 是仓库的 Owner,G 是 Group(含 B、C),D 是与该文件无关的成员,所以是 Others。当初入职了一个用户 E,因为 E 是新人,所以不想让 E 去操作代码,只容许他查看相熟代码。

面对这种场景,试想一下如何给 E 成员设置对应权限呢?答案是 oh no,因为 E 既不能依照 G 组权限,也不能依照 Others 权限,更不能是 Owner!所以面对这种鸡肋的权限,ACL 就作为了其补充,ACL 能够反对针对某一个用户或某个用户组做独立的权限,完满解决了相似场景。

二、PingCode Wiki 权限架构

OK,理解了什么是 ACL 以及应用场景,咱们来聊一下 Wiki 的权限架构,根本架构见下图。

1. 根底权限 RBAC——角色对应的权限

1.1 权限配置

1.2 查看权限

2. 页面权限 ACL——针对用户和用户组的权限

页面权限同样是作为 RBAC 的补充,更加细粒度的权限划分,即给某局部人或某局部用户组调配对应权限。

2.1 页面权限设置入口

右上角菜单——「更多 - 权限设置」

2.2 独立权限与共享权限

独立权限——「权限设置 - 知识库成员」

共享权限——「权限设置 - 非知识库成员」

从咱们的需要(针对用户和用户组局部人群)来看是合乎 ACL 解决方案的。

三、设计与实现

到这里的同学置信曾经对 Wiki 权限性能有了大抵的理解,上面开始具体介绍一下开发中的设计细节,关键点、难点以及计划的选用取与舍。

1. 关系模型与数据库设计

理解根本需要,自己依据以往的开发教训简略的定了一个初步计划,见下图计划 A,起初对照原型和设计图调整了一些细节,产生了计划 B,见下图。
A 计划

B 计划(最终计划)

两种计划的区别:

A 计划是关系型数据库的常见设计,以用户 / 用户组为主导映射模块和权限,对应关系为:多对多 用户 / 用户组(user/group) ——> 资源(pageId)
B 计划,以模块为主导映射用户 / 用户组,一对多:资源(pageId)——> 用户 / 用户组(scopes)

思考到权限是全量保留的,正是因为这种交互方式所以调整出了 B 计划,而且服务端数据库是 mongodb,反对数组的个性,十分的符合。

2. 对应的程序实现

资源或模块(pageId)——> 用户 / 用户组(scopes),实体对应关系

字段 类型 形容
scopes Array<Schema> 权限设置具体
permission_type Enum 权限类型
principals ScopeDesignation[] 指定具体
type ScopeDesignationType 指定类型
id UIDlID 人 / 用户组 / 部门的惟一标识
value number 权限值

权限值计算参考了 Linux,采纳的是位运算:1、2、4、8…

  • 领有的权限值累计取最大 mask 值:只读 1 + 编辑 2,最终数据库存 3。
  • 判断是否领有某个权限值:权限值 & 预期的权限值 = 存在 / 预期的权限值。

    3. 约定 API

    还是因为保留交互决定了增加、批改、删除是一个 API。

  • 保留(增加 / 批改 / 移除): {put}/api/wiki/spaces/:spaceId/pages/:pageId/permission$ 
  • 获取: {get} /api/wiki/spaces/:spaceId/pages/:pageId/permission/:scopeType$ 

    4. 波及的简单场景

    权限波及的简单场景十分的多,以下场景探讨和决定经验了很多挫折,某些性能中途重做了两次,迭代向后推延了一周,两次会议,共继续大概两个半小时,因为文章篇幅,只列举局部场景作为交换。

    4.1 权限继承(简单场景)

    第一个难解决的点就是权限继承,的确很绕,置信很多产品都遇到过相似场景(具体是哪些这里不赘述了),自己从技术和产品的角度都参考过 Linux 的解决,但因为零碎级别和利用还是有些许不同,做了一些调整,上面列举的是咱们做过的计划。
    第一版:子页面齐全继承父页面且不可更改

  • 父页面不可见,子页面不可见
  • 父页面只读,子页面编辑,最终子页面是只读
  • 父页面编辑,子页面只读,最终子页面是编辑

不满足的场景和逻辑的冲突点:

  • 父页面容许查看,预期某些子页面容许查看,某些子页面不可查看
  • 父页面容许查看但不许编辑,预期某些子页面凋谢编辑权限
  • 父页面容许编辑,但某些子页面不容许编辑

第二版:子页面容许独立权限,默认继承父权限
页面继承逻辑:子页面一旦设置,中断与父页面的继承关系,中断后权限类型能够改

  • 父级页面设置权限后,子级页面不设置权限,默认继承父级权限;
  • 子级页面设置权限后,不再继承父级权限,造成本人独自的页面权限

4.2 中间件逻辑

中间件波及的场景也比拟多,比方单页面详情查看,拖拽挪动以及跨知识库挪动,复制,删除等等,外围的验证逻辑如下图。

4.3 页面树展现及权限计算(难点)

4.3.1 展现逻辑

会议上,探讨页面树的展现的可选计划如下:

  • 展现全副层级页面,依据权限可见内容(存在题目私密性问题,层级过多后,会看到多个不可见的题目,摈弃
  • 只展现有权限的页面,把子页面提出来(层级构造打乱了,摈弃
  • 落地计划:只展现有权限的页面,当父页面不可见时,子页面可见时,把父页面展现进去,如果没有可见的子页面时父页面也不可见(计划二)— 父页面不可见的题目用灰色展现(点击成果保留),点击后右侧无权限页面
  • 间接暗藏父与子(已实现计划一,仅能通过告诉查看,入口少,扭转继承关系后,不太实用,摈弃

最终确定的是一个折中计划,如果子页面有权限,那么会把父页面也展现进去,保障树结构的完整性,若以后页面和子页面都没有权限,那么就过滤掉。如下图

4.3.2 权限计算(技术难点)

难点:

  1. 页面树波及到继承
  2. 全量的计算(弄不好须要递归解决),所以程序计算复杂度要思考
  3. 过滤逻辑(子有查看权限,父肯定展现)

解决伎俩

  1. 数据库存储 parent 和 parent_ids 字段,parent_ids 依照树的层级拍平排序,比方树的层级是 A->B->C,parent_ids 贮存的是 [A,B,C]。
  2. 把列表数据宰割成两组,一组是所有的页面,另一组是所有作为了父页面的,具体怎么查问只须要验证 parent_id 是否存在即可,属于数据库操作。
  3. 把 List 数据结构转换成 Map 或 Set,缩小迭代次数来升高复杂度。

具体解决逻辑
筹备工作:

  1. 从数据库中取出 以后知识库的页面列表数据和页面对应的 ACL 权限列表
  2. 将页面列表拍平转换为 Map(为了上面缩小复杂度)
  3. 将权限列表拍平转换为 Map(目标同上)
  4. 取出 RBAC 的知识库权限
  5. 用来解决子页面可见,父页面不可见,而须要展现的父页面汇合 Set(在上面会具体解说具体用途)
  6. 最终要 页面列表(含权限值)

如下图(为了不便后续的解说,特标注序号)

解决流程,如下图:

  1. 迭代页面列表
  2. 取出一个页面,找对应权限
  3. 如果找到了设置的对应权限,那么合并 RBAC 权限放入最终的后果集,没有找到执行上面逻辑 a. 通过以后页面的 parent_ids 按倒序迭代(下面解决伎俩已解说 parent_ids 的排列程序)
    b. 如果没有父级或所有父级均没有权限,则持续最外层迭代,反之取出最近有权限的父级页面,并且将父级页面与以后页面之间的页面放入 ⑥(Set)中,这块大家可能有疑难,举个例子:假如有 3 个页面,A、B、C,C 的父级是 B,B 的父级是 A,以后迭代的是 C,C 没有权限,B 也没有权限,A 有权限,那么最终将 A、B 推入 Set 中,C 因为继承逻辑 也领有权限。
  4. 将 Set 中的父级页面补充到最终的后果集
  5. 持续迭代,直至结束

最初发现 ⑥ 是为了补充缺失的一部分数据:子页面可见,父页面不可见,但要展现的父页面
大家可能从下面环节还有一个疑难就是为什么要合并 RBAC 知识库权限,请接着看。

4.4 权限相干非凡解决

下面谈到了曾经验证出页面权限,但还是合并了知识库权限,是因为产品逻辑中有以下规定:

  1. 知识库没有编辑权限,页面权限有,那么最终有编辑权限,所以要笼罩知识库的编辑权限。
  2. 领有只读权限的成员不能执行的操作:
  • 不能创立子页面
  • 不能删除以后页面
  • 不能挪动以后页面
  • 不能挪动至只读的页面下(对指标页面来说实际上是增加页面)
  • 不能复制页面
  • 不能复制至只读页面下
  • 不能发布页面
  • 不能重命名页面
  • 不能进入编辑页面

留神的是切勿漏掉场景。

4.4.1 集体对后续的构想

针对于这些非凡解决,个人感觉究竟不是解决方案,而且后续新加或移除权限,都要兼顾多处,技术角度保护起来艰难,也容易漏掉,所以构想页面也退出更多权限点,让用户来被动勾选所须要和禁止的权限,技术上就能够对立一套逻辑。

五、写在最初

下面只是列举了一些通用和些许简单的场景,理论开发中还有很多的细节,所以开发期间很忙,经验了头脑风暴,也有走误区的及时调整和反思,这些都是贵重的教训。

最初谈谈开发至今的一些感悟:

  • 团队之间及时沟通,充沛了解需要,建设对立认知,防止把烟囱做成水井的糗事,也缩小相互甩锅的状况,对团队有良好的作用,值得一提的是 Wiki 团队秉承着这一低劣习惯,与 Wiki 这款产品的价值观相符合。
  • 技术人员要踊跃思考需要,优先站在用户和产品角度思考,其次再思考技术,切勿过于执着技术,却疏忽了用户和产品的初衷。
  • 技术人员对每一行代码负责,别把技术债留给本人或他人,代码终将会回馈团队和你本身。
  • 要做好细节,作为还是技术都要做好细节,“刚”到可能是细节决定的成败。

到这里完结了,非常感谢每个看到这里的同学,有任何疑难欢送探讨交换。

欢送关注 Wiki,关注 PingCode 研发核心


最初,举荐咱们的智能化研发管理工具 PingCode 给大家。

PingCode 官网

对于 PingCode

PingCode 是由国内老牌 SaaS 厂商 Worktile 打造的智能化研发管理工具,围绕企业研发治理需要推出了 Agile(麻利开发)、Testhub(测试治理)、Wiki(知识库)、Plan(我的项目集)、Goals(指标治理)、Flow(自动化治理)、Access(目录治理)七大子产品以及利用市场,实现了对我的项目、工作、需要、缺点、迭代布局、测试、指标治理等研发治理全流程的笼罩以及代码托管工具、CI/CD 流水线、自动化测试等泛滥支流开发工具的买通。

自正式公布以来,以酷狗音乐、商汤科技、电银信息、51 社保、万国数据、金鹰卡通、用友、国汽智控、智齿客服、易快报等知名企业为代表,曾经有超过 13 个行业的泛滥企业抉择 PingCode 落地研发治理。

正文完
 0