我如何建立关系模型(GitHub-like)权限?

How do I model (GitHub-like) permissions relationally?

tl;dr:我如何实现权限模型(例如)github's

已更新以尝试解决@philipxy 的一些评论:

我计划实施类似于 github 的权限模型:

  1. 用户
  2. 用户可以分组
  3. 用户可以在组织中
  4. 组可以在组织中
  5. 用户将被允许对资产、组或组织执行任何 C、R、U 和 D 操作 as
    1. 已被允许执行那些(C、R、U、D 中的任何一个)操作的个人用户
    2. 已被授予这些权限的组成员
    3. 已被授予这些权限的组织成员
      1. 或作为组的成员,该组属于具有权限的组织
  6. 用户被授予读取权限,因为 asset/group/org 对匿名用户 ("public")
  7. 可见(可读)
  8. 用户还应该有一组权限,说明他们是否可以对权限执行 C、R、U 或 D 中的任何一项(用户可以创建权限 [C,R,U,D]另一个用户、组或组织)
    1. 用户可以为他们创建的任何资产、组或组织设置权限,或者为他们有权设置权限的任何资产、组或组织设置权限。

这些权限将控制谁可以对站点中的资产、组和组织执行创建、读取、更新和删除 (CRUD) 操作。

大概如何建模?

显然我有这些模型:

  1. 资产
  2. 用户
  3. 群组
  4. 组织

下一步是什么?

  1. 许可?
  2. PermissionType(捕获C/R/U/D)?

我正在使用节点中的 mysql(通过 sequelize),但我自己可以弄清楚具体的语法,我只是还没有弄清楚如何从概念上做到这一点。

@philipxy 的更多观点:

你建议我做更多的事情确实是我想寻求帮助的事情。也就是说,那些信息设计方法(NIAM、FCO-IM、ORM2、IDEF1X)正是我要找的。我对关系数据库 实现 了解很多(学习规范化和范式等等的日子),但确实指定业务需求并将其转换为可操作规范的过程是一个挑战。

我想我要去拿一本数据库教科书。

关于谓词的更多工作:

  1. U 标识一个 User
  2. A 标识一个 Asset
  3. G 标识一个 Group
  4. a User U可以在0个或多个Groups G
  5. O 标识一个 Organization
  6. a User U 可以在0个或多个 Organizations O
  7. a Group G可以在0个或多个Organizations O
  8. 资产 A 可以由 User U
  9. 创建
  10. Assets 上的 CRUD:
    1. 可以允许 Entity E(通过 Permission P ?)在 Assets[=243 上执行操作 Ac =]
    2. 那些Actions是:
      1. Create
      2. Read
      3. Update
      4. Delete
    3. Entity可能是以下类型:
      1. User
      2. Group
      3. Organization
      4. Anonymous User/"the public"
    4. 详细信息(仅显示 Read,但也与 CreateUpdateDelete 相关):
      1. 一个UserU0可以允许另一个UserU1Read一个AssetA
      2. a User U0 可以允许属于 Group GUsers U Read Asset A
      3. a User U0 可以允许 Users U Organization O 的成员 Read Asset A
      4. Users U in Group G1,其中 G1Group,它位于 Organization O 已被允许 Read Asset A,因此被允许 Read Asset A
  11. a Permission P 引用 Asset A 只能由某些用户创建:
    1. 默认情况下,Entity 的创建者 User U 可以为 Entity
    2. 创建 Permissions
    3. 但他们可能只引用他们拥有 PermissionAssets(在基本情况下:那些 AssetsU 创建)
    4. a User 获得 Grant(?) 权限的人也可以在 Permission
    5. 中引用 Entity E
    6. Gr 标识一个 Grant
      1. a Grant 授予 Entity 创建、读取、更新或删除引用另一个 Entity
      2. Permissions 的权限
      3. PermissionsGrants一样具有传递性:
        1. 如果 Organization O 已获得 Granted 特权(例如)为 Entity E 修改 Permissions,则
        2. 不仅 O 的成员 Users 可以修改引用 EPermissions
          1. 而且 Users 是任何 Group G 的成员,其中 GO 中,有权修改 Permissions引用 E

谓词和tables

命题 是对业务情况的真假陈述。 predicate 是一个 column-parameterized 语句,给定一行给出一个命题。 table(基础或查询结果)包含从其谓词中得出真命题的行。

user (with id) U has name N
R is a grantor (may grant permissions)

user U has permission to update asset A
grantor R gave permission to grantor E to use an operator of type 'CRUD'
grantor E is of type 'user' AND grantor E has permission to update assets

业务规则

业务规则是 always-true 定义术语或描述策略或流程的语句。

A user is uniquely identified by an id assigned when their cheque clears.  
A crudable is an asset, group or organization.  
A grantor is a user, group, organization.
"Grantee" refers to a grantor receiving or holding a permission.    
Users can be in organizations.  

您可以创建无参数谓词的真语句。这些可以使用由 FOR ALL & FOR SOME (THERE EXISTS) 绑定的参数名称。根据此类命题谓词 and/or table 名称表述的业务规则是 数据库约束 。给定 User(U,N) & Grantor(R) 作为上面前两个谓词的简写作为 tables User & Grantor 的谓词,下面几行都说同样的事情:

A user is a grantor.
FOR ALL U, if U is a user then U is a grantor.

FOR ALL U, (FOR SOME N, User(U, N)) IMPLIES Grantor(U).
(SELECT U FROM User) ⊆ (SELECT R AS U FROM Grantor).

FOR ALL U & N, User(U, N) IMPLIES Grantor(U).
FOR ALL U & N, (U, N) IN User IMPLIES (U) IN Grantor.

FOREIGN KEY User (U) REFERENCES Grantor (R); 说明上面的内容(注意它与中间两个的相似性)加上 R 在 Grantor 中是 UNIQUE NOT NULL。

不要混淆规则和谓词。它们有不同的用途,通常有不同的形式。 (一个无参数的句子模板可以用作任何一个。)规则是一个真实的陈述;谓词是参数化语句。看看我的回答如何将它们区分开来。基tables和查询结果tables有谓词。但是一条规则可能会建议你需要一个 base predicate/table 来记录一些东西。当我们从一条规则中看到我们必须记录一些关于当前情况的陈述时,我们就有了基础predicates/tables。请注意,某些规则不会激发基本谓词。

您可能想要重新定义类型和权限。

A user is a grantor of type 'user'.
Permission named 'C' is permission for a grantee to create a crudable.

Grantor E is of type 'user'.
Permission P is of type 'CRUD'.
Grantor R gave permission P of type 'CRUD' on crudable C to grantee E.

设计是寻找充分必要的规则和基本谓词

这里有相关的谓词来记录你的阐述暗示出现的情况。

  1. users
U identifies a user
  1. users can be in groups
G identifies a group
user U is in group G
  1. users can be in organizations
O identifies an organization
user U is in organization O
  1. groups can be in organizations
group G is in organization O
  1. a user will be permitted CRUD operations on an asset, group, or organization
A identifies a crudable of type 'asset'
user U is permitted CRUD operations on crudable C

5.1 as an individual user, or as a member of a group, or as a member of an organization (or as a member of a group where that group belongs to an org that has permissions),

P identifies a permission
organization O is permitted CRUD operations on crudable C

or because the asset/group/org is viewable (readable) to anonymous users ("public")

crudable C is public
  1. a user should also have a set of permissions to say whether they can set the above permissions
grantor R has permission to set CRUD permission for users on crudable C --?  

什么是"the above permissions"?也许你的意思是用户 CRUD 权限和组织 CRUD 权限?也许您的意思是创建、读取等操作有单独的权限?你需要更清楚。

"a set of permissions" 中的权限是什么?这里的 "permission" 是指 "particular permission to a particular grantee" 吗?你需要更清楚。

更清晰的方法是提供尽可能简单但又不至于简单到没有提及相关内容的规则和谓词 entities/values。之后您可能希望将多个规则和谓词概括为单个规则和谓词。例如,不是与用户、团体、组织和资产打交道,而是有授予者和 crudables:Grantors may grant permissions. & grantor R gives permission P to grantee E。如果某些此类权限也与特定的受赠者相关联,您可能还需要像 grantor R gives permission P to grantee E re permission Q and grantee F.

这样的谓词

6.1. a user can set the permissions for any asset, group, or org they create,

user U created crudable C

or any asset, group, or org for which they have been given permission to set permissions.

user U has permission to set permission P for crudable C --?  

你会想要记录这样的事情 user U has name N and ...

了解数据库设计

搜索 database/SQL subtyping/inheritance/polymorphism 成语。例如,用户、组和组织是权限拥有者和持有者的类型;我将它们设为类型授予者的子类型。也许你想要某种权限目标类型,它是 crudable 和 grantor 的联合体。也许你想要权限类型。也许某些许可权限具有关联的受让人。也许'C'、'R'、'U' & 'D'是权限,'CRUD'是一种权限。您可能想记录什么授予者授予了被授予者什么权限。

稍后我们可以用它们的连接替换 tables,如果连接在共享 PK/UNIQUE 上并且两者中的值集相同。当我们可以加入 PK/UNIQUE & FK 时,我们可以将 tables 替换为类似他们的加入但 FK 可为空。还有一些时候我们可以毫无问题地将多个 table 替换为一个。但首先确定基本谓词。

了解关系数据库设计。遵循一些信息设计方法。最好的是 NIAM/FCO-IM/ORM2 家族的成员。查看 IDEF1X。不要依赖产品。

了解约束。他们遵循 谓词和业务规则。它们是关于谓词方面可能的业务情况的真相。等价地,它们是关于 table 的可能数据库状态的真相。还了解 SQL 中的约束,包括声明性(PK、UNIQUE、FK)和触发。

好吧,当您尝试使数据库的行为方式与 Github 相同时,问题就来了。数据库有一个完全不同的范例。这就是为什么基于 C# 的工作方式设计数据库同样糟糕。不同的功能或规则。然而,这是一个有趣的问题,因为很少有人将权限模型作为其数据库设计的一部分加以注意,而只是授予每个人对所有内容的权限,因为这更容易。

首先,用户不应该能够授予其他人权限,只有管理员才能这样做。如果你有一个好的数据库设计,用户不应该创建对象。数据库设计与业余爱好者无关。

用户可以是个人,也可以使用应用程序用户,其中来自特定应用程序的所有数据库请求都具有相同的权限。应用程序甚至可以有多个通用用户,例如 XYZAdmin、XYZUser、XYZReadonly(通常用于需要能够查看数据但不打算调整数据的高级管理人员。)。根据我的经验,通用用户的最大问题是很难审核谁更改了数据库中的内容(在受监管的环境中非常重要),并且某些用户可能拥有比他们真正需要的权限更多的权限。

在数据库中,您有几种基本类型的权限。您拥有扩展到整个数据库和对象级别权限的权限。您还拥有一些特定的服务器权限,例如使用批量插入或执行作业的权限。由于大多数数据库服务器都有多个数据库,因此还应授予组关于他们可以在服务器上看到哪些数据库的权限。因此,您可以授予用户写入任何 table 的权限,或者不授予他们对 table 的权限,而只授予他们对特定存储过程或视图的权限。一般来说,管理人员获得对所有内容的总体权限(或服务器级权限,如批量插入权限)。这包括拥有完全权限的 DBA 和其他专家,例如数据 analysts/senior developers/build 团队成员,他们可能只拥有与工作和数据输入或创建新对象相关的权限,但没有执行设置权限等任务的权限。所有其他用户都应锁定在对象级别权限中。

现在任何人都不应该被授予个人权限(或者至少这应该是一件罕见的事情)。每个人都应该属于拥有权利的不同群体。个人可以在多个组中,并且这些权限如何在组之间交互可以在与您正在使用的特定数据库产品相关的文档中进行解释(是的,这是特定于产品的,没有一种尺寸适合所有数据库权限模型。)这样做的好处是,当某人不再是用户时,您只需将他们从组中删除,权限就会消失,而不是搜索大量的个人权限。

现在当您按组处理权限时,您需要定义组。如果您希望一个组只对记录或列的一个子集而不是整个 table 具有权限,您可能还需要定义一些额外的视图或存储过程。如果您在一个数据库中有多个客户端并且需要确保权限仅适用于一个特定的客户端,那么您需要使用存储 procedures/views 并仅在存储 procedure/view 级别而不是 table级。将视图用于权限可能会变得棘手,因为每个数据库产品都有关于什么使视图可更新的特定规则。您需要深入了解这一点,以确定您将如何管理权限。

创建的所有数据库对象都需要编写脚本,作为创建脚本的一部分,特定组被授予对该对象的权限。 (您永远不会通过任何类型的 GUI 创建数据库对象,总是通过保存在源代码管理中的脚本。)

您还可以通过设置一些数据库 table 来为客户端做一些权限工作,其中包含有关用户可以访问的特定页面或允许他访问的特定客户端的元数据。然后当应用程序加载时,来自这些 table 的用户数据被加载,应用程序将决定他或她可以做什么。坦率地说,这更容易,但可能会有风险。

这意味着用户必须具有 table 级别的权限,而用户实际上不应该具有这些权限。因为数据库级别的权限更广泛,恶意用户更容易在应用程序之外登录并做他或她不应该做的事情。如果您的内部用户可以通过用户应用程序以外的其他方式(例如 SQL 服务器的 SSMS)轻松登录,则需要特别注意这一点。

如果你的数据库应用程序是在法律监管的领域,比如金融或医疗保健,你需要对权限非常严格,并且使用 ORM 而不是存储过程是禁忌的,因为你在任何时候都不应该设置权限table级。

在我看来,您需要创建一个实体的概念,该实体可以接收存储库或组织的权限。

在此模型中,问题变得相对简单,因为权限将围绕 RepositoryPermissions table 形式:

(EntityId, RepositoryId, canCreate, canRead, canUpdate, canDelete)

和一个 OrganizationPermissions table 的形式:

(EntityId, OrganizationId, canCreate, canRead, canUpdate, canDelete)

有两种类型的实体GroupsUsers,任何用户的权限都需要通过四种方式进行检查:

  • 直接用户 存储库 级别
  • 权限
  • User Group 的成员资格,具有 Repository 级别的权限
  • 用户 组织 级别
  • 的直接权限
  • User 属于 Group,具有 Organization 级别的权限。

以下查询应检索与存储库 someRepoId

上的用户 someUserId 有关的所有权限条目
    SELECT
      rp.canCreate,
      rp.canRead,
      rp.canWrite,
      rp.canDelete
    FROM RepositoryPermissions AS rp

    Left JOIN Users      AS u  ON u.EntityId = rp.EntityId
    Left JOIN Groups     AS g  ON g.EntityId = rp.EntityId
    Left JOIN GroupUsers AS gu ON gu.GroupId = g.GroupId

    WHERE rp.repositoryId IS "someRepoId" AND (
      u.UserId IS "someUserId" OR
      gu.UserId IS "someUserId"
    )
UNION
    SELECT 
      op.canCreate,
      op.canRead,
      op.canWrite,
      op.canDelete
    FROM Repositories AS r
    JOIN OrganizationPermissions AS op ON r.repositoryId = op.repositoryId

    Left JOIN Users      AS u  ON u.EntityId = op.EntityId
    Left JOIN Groups     AS g  ON g.EntityId = op.EntityId
    Left JOIN GroupUsers AS gu ON gu.GroupId = g.GroupId

    WHERE r.repositoryId IS "someRepoId" AND (
      u.UserId IS "someUserId" OR
      gu.UserID IS "someUserID"
    )