复杂应用程序的高性能 ACL 模式(RDBMS、图形数据库?)

Ben*_*n M 7 permissions rdbms acl authorization neo4j

我正在使用 Java/Spring 和至少 2 个不同的数据库构建一个相当复杂的 Web 应用程序:

  • 主数据的关系型数据库
  • MongoDB 用于文件(通过 GridFS)和其他数据 CLOB/JSON/等。

下一步是授权。简单的基于角色的授权是不够的,因为应该允许/禁止用户查看/修改不同的资源。虽然我想到了 ACL。

最常见的简单 ACL 表可能如下所示:

TABLE  | FIELDS
-------+--------------
class  | id, className
object | id, class_id, objectId
acl    | id, object_id, user_id, permissionBitMask (crud)
Run Code Online (Sandbox Code Playgroud)

但不幸的是,这不足以满足我的需求:(

我也需要:

  • 角色
    • 每个用户可以有多个角色,并且
    • ACL 条目也可以属于一个角色
  • 更多权限
    • 例如:每个项目可以有多个任务不能修改项目详细信息的用户为该项目创建新任务。所以必须有一个单独的许可。
  • 不同类型的 ObjectId
    • RDBMS 表将使用 UUID 代理键(所以至少我不必在这里处理复合键)
    • 但是 MongoDB 当然使用它自己的 ObjectId
    • 此外,我将在代码中包含一些静态资源,这些资源也必须受到访问限制。
  • 父对象继承权限

如果我结合所有这些方面,我会得到以下表格结构:

TABLE          | FIELDS
---------------+--------------
class          | id, className
object         | id, class_id, objectId, parent_object_id
acl            | id, object_id, user_id, role_id
permission     | id, permissionName
acl_permission | id, acl_id, permission_id, granted
Run Code Online (Sandbox Code Playgroud)

当然我可以拆分 acl表为 2 个表(1. 对象 + 用户,2. 对象 + 角色),但我认为这并不重要。

“objectId”将是一个简单的 VARCHAR,我的应用程序必须将它从/转换为字符串。否则,对于不同的 ObjectId 类型,我还有 5 个附加表。这将导致 5 个额外的 JOIN 操作......

现在基本的查找查询将是这样的:

SELECT p.granted
  FROM acl a
  JOIN acl_permission p
    WHERE p.permission_id = ?
      AND (
           a.object_id = ? AND a.user_id = ?
        OR a.object_id = ? AND a.role_id IN (?)
      )
Run Code Online (Sandbox Code Playgroud)

(权限被缓存,当前用户的角色也通过会话上下文缓存。granted只是表明,如果用户有权限。)

然后,如果当前对象没有 ACL 条目,我还必须应用递归 SELECT,以获取父对象的 ACL。

这不能真正发挥作用。那么有哪些替代方案呢?我的想法:

  • 不同的数据库模式(任何想法!?)
  • 图形数据库,如 Neo4j。

Neo4j优点:

  • 查找具有权限条目的第一个父级是此数据库的一项简单任务
  • 在 ACL 条目中存储一系列权限是可能的,->没有 JOIN
  • 基本上我可以将所有信息存储在一个节点中:

.

{
  class: ClassName,
  object: ObjectId,
  parent: RelationToParentNode,
  user: UserId,
  role: RoleId,
  grantedPermissions: [Permission1, Permission2, ...]
}
Run Code Online (Sandbox Code Playgroud)

(未在数组中列出的每个权限都不会自动授予。不可能在 Neo4j 数组中存储复杂类型,因此无法存储类似的内容permissions: [{Permission1: true}, {Permission2: false}]

当然,也可以将权限和类存储为单独的节点,然后将它们链接在一起。但我不知道 Neo4j 的更好方法是什么。


对此有何想法?有没有开箱即用的解决方案?也许有理由将 MongoDB 用于 ACL?

我读过 XACML 和 OAuth(2),但两者似乎都需要一个额外的 ACL 模式来做我需要的。还是我错了?

Eye*_*Eye 4

首先,您正在寻找的复杂权限系统有一个称为RBAC(基于角色的访问控制)的标准规范。我已经在 SQL 中实现了各种简单和复杂的 RBAC 模型。工作正常,当关系数量增长到百万以上时,SQL 在商用硬件上的执行速度并不快。读取是即时的,但写入速度很慢,因为为了提供快速读取而复制记录的工作量很大。

最初,当我设计权限系统时,我实际上是根据 RBAC 规范将其“绘制”在纸上。输出确实是一张图表。因此,经过两年的生产使用后,我正在考虑切换到本机图形数据库。

Neof4j 是一种流行的解决方案,但由于其薄弱的集群和复制系统,一些重要客户似乎对其不满意。所以看看 OrientDB(参见OrientDB 与 Neo4j)。

您在上面提到“不可能在 Neo4j 数组中存储复杂类型”。OrientDB 声称已经通过自定义数据类型解决了这个问题。我还没有亲自尝试过,但计划在迁移我们的生产数据后进行测试。