我正在使用Java / Spring构建一个相当复杂的Web应用程序,并且至少有两个不同的数据库:
- 主数据的关系型数据库
- MongoDB 用于文件(通过GridFS),以及其他数据CLOBs / JSON等。
下一步是授权。简单的基于角色的授权不足以满足需求,因为用户应该被允许/禁止查看/修改不同的资源。尽管我想到了 ACL。
最常见的简单ACL表格可能如下所示:
TABLE | FIELDS
-------+--------------
class | id, className
object | id, class_id, objectId
acl | id, object_id, user_id, permissionBitMask (crud)
但是很遗憾,这对我的需求来说还不够
:(
。我还需要:
- 角色: - 每个用户可以有多个角色, - 一个访问控制列表条目也可以属于一个角色。 - 更多权限: - 例如:每个项目可以有多个任务,但是具有修改项目详情权限的用户不能创建此项目的新任务。因此必须有单独的权限进行控制。 - 不同类型的对象ID: - 关系型数据库表将使用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
当然,我可以将表拆分为两个表(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 (?)
)
权限被缓存,当前用户的角色也通过会话上下文进行了缓存。granted
仅指示用户是否具有该权限。
然后,我还需要应用递归SELECT,以便在当前对象没有ACL条目时获取父对象的ACL。
这不太高效。那么有什么替代方案吗?我的想法:
- 不同的DB模式(任何想法!)
- Neo4j等图形数据库。
Neo4j优势:
- 查找具有权限条目的第一个父级对于此DB来说是一项简单的任务
- 在ACL条目中存储权限数组是可能的
->
无需JOIN - 基本上,我可以将所有信息存储在单个节点中:
.
{
class: ClassName,
object: ObjectId,
parent: RelationToParentNode,
user: UserId,
role: RoleId,
grantedPermissions: [Permission1, Permission2, ...]
}
(除了在数组内列出的每个权限外,所有其他权限都自动未被授予。在Neo4j数组中无法存储复杂类型,因此无法存储诸如
permissions:[{Permission1:true},{Permission2:false}]
之类的内容。)当然,也可以将Permissions和Classes作为单独的节点存储,并将它们全部链接在一起。但是我不知道在Neo4j中使用哪种方法更好。
这方面有什么想法吗?是否有现成的解决方案?也许使用MongoDB实现ACL有其原因?
我了解了XACML和OAuth(2),但似乎都需要额外的ACL模式才能满足我的需求。或者我错了吗?