权限和访问控制
图数据库用于权限和访问控制
授权和访问控制解决方案存储有关各方(例如,安全管理员)和资源(例如,业务用户和所有者)的信息,以及管理对这些资源访问的规则。然后,他们应用这些规则的控制系统来确定谁可以代表其他用户访问或操作一组操作。访问控制传统上是通过使用目录服务或通过在应用程序的后端构建自定义解决方案来实现的。不幸的是,在关系数据库上开发的分层目录结构随着数据集大小的增长而遭受连接痛苦,变得缓慢且无响应,最终提供糟糕的最终用户体验。
复杂性带来麻烦
使用像 Neo4j 这样的图数据库进行访问控制的关键好处是,引入高度风险的复杂需求会大大降低。当业务部门请求一组用于访问控制用例的需求时,负责交付系统的软件开发人员往往会遇到相当多的阻力。这种阻力就是我所说的软件工程项目的“复杂性妥协”。
本教程涵盖的内容
与网络管理和分析一样,图数据库访问控制解决方案允许自上而下和自下而上的查询。本教程将探讨如何使用 Neo4j 和 Cypher 来确定
-
特定安全管理员可以管理哪些资源——公司结构、产品、服务、协议、帐户和最终用户?
-
最终用户可以对哪些资源执行操作?
-
给定特定资源,谁可以修改其访问设置或权限?
ACME 系统的访问控制
本教程说明了虚构公司 ACME Systems 的组织结构。在 ACME Systems 中,安全管理员被分配到一个或多个用户组,这些用户组通过下面描述的继承关系连接到一些而非全部公司。如果公司未连接到用户组,它将继承父公司的安全管理员权限。
每个公司都通过WORKS_FOR
关系分配一个或多个业务用户,并且每个业务用户都通过HAS_ACCOUNT
关系分配一个或多个帐户。
-
ALLOWED_INHERIT
将安全管理员组连接到组织单元,允许该组内的安全管理员管理该组织单元。此权限由父组织单元的子级继承。 -
ALLOWED_DO_NOT_INHERIT
以一种允许该组内的管理员管理组织单元但不管理其任何子级的方式将安全管理员组连接到组织单元。 -
DENIED
禁止安全管理员访问组织单元。此权限由父组织单元的子级继承。DENIED
优先于ALLOWED_INHERIT
,但从属于ALLOWED_DO_NOT_INHERIT
。
访问控制级别及其交互
尽管不太复杂,但此 GraphGist 具有许多相互关联的部分。在探索不同类型的访问控制时,让我们从简单的查询到复杂的查询逐步进行。
ALLOWED_INHERIT
同样,ALLOWED_INHERIT
将管理员组连接到组织单元,从而允许该组内的管理员管理该组织单元。此权限由父组织单元的子级继承。
在 ACME Systems 中,安全管理员 Ben 可以管理 Skunkworks 和 Spinoff 两家公司的员工,这要归功于 Group1(Ben 是成员)与 Acme 之间以及 Group1 与 Startup 之间的ALLOWED_INHERIT
关系。
MATCH paths=(admin:administrator {name:'Ben'})-[:MEMBER_OF]->()-[:ALLOWED_INHERIT]->(c1:company)<-[:CHILD_OF*0..3]-(c2:company)<-[:WORKS_FOR]-(employee)-[:HAS_ACCOUNT]->(account)
RETURN admin.name AS Admin, c1.name AS `Parent Company`, c2.name AS `Child Company`, employee.name AS Employee
ALLOWED_DO_NOT_INHERIT
同样,ALLOWED_DO_NOT_INHERIT
以一种允许该组内的管理员管理组织单元但不管理其任何子级的方式将管理员组连接到组织单元。Sarah 作为 Group 2 的成员,可以管理 Acme,但不能管理其子级 Spinoff,因为 Group 2 通过ALLOWED_DO_NOT_INHERIT
关系而不是ALLOWED_INHERIT
关系连接到 Acme。
此查询探讨了由于ALLOWED_DO_NOT_INHERIT
关系,管理员 Sarah 不允许管理哪些用户
MATCH paths=(admin:administrator {name:'Sarah'})-[:MEMBER_OF]->()-[:ALLOWED_DO_NOT_INHERIT]->(c1:company)<-[:CHILD_OF*1..3]-(c2:company)<-[:WORKS_FOR]-(employee)-[:HAS_ACCOUNT]->(account)
RETURN admin.name AS Admin, c1.name AS `Parent Company`, c2.name AS `Child Company`, employee.name AS Employee
DENIED
同样,DENIED
禁止管理员访问组织单元。此权限由父组织单元的子级继承。在 ACME Systems 中,这最好通过管理员 Liz 及其相对于 Big Co、Acquired Ltd、Subsidiary 和 One-Map Shop 的权限来说明。
让我们看看 Liz没有DENIED
限制的情况
MATCH paths=(admin:administrator { name:'Liz' })-[:MEMBER_OF]->()-[:ALLOWED_INHERIT]->(:company)<-[:CHILD_OF*0..3]-(:company)<-[:WORKS_FOR]-(employee)-[:HAS_ACCOUNT]->(account)
RETURN paths
让我们看看 Liz有DENIED
限制的情况
MATCH paths=(admin:administrator { name:'Liz' })-[:MEMBER_OF]->()-[:ALLOWED_INHERIT]->(:company)<-[:CHILD_OF*0..3]-(c:company)<-[:WORKS_FOR]-(employee)-[:HAS_ACCOUNT]->(account)
WHERE NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(c))
RETURN paths
由于她属于 Group 4 并在 Big Co 上拥有ALLOWED_INHERIT
权限,Liz 可以管理 Big Co。但是,尽管这是一种可继承的关系,但 Liz 无法管理 Acquired Ltd 或 Subsidiary。Liz 所属的 Group 5 被DENIED
访问 Acquired Ltd 及其子级(包括 Subsidiary)。
但是,Liz 可以管理 One-Map Shop,这要归功于授予 Group 6(Liz 属于的最后一个组)的ALLOWED_DO_NOT_INHERIT
权限。
让我们再次查看该查询,这次添加ALLOWED_DO_NOT_INHERIT
MATCH paths=(admin:administrator {name:'Liz'})-[:MEMBER_OF]->()-[:ALLOWED_INHERIT]->()<-[:CHILD_OF*0..3]-(c:company)<-[:WORKS_FOR]-(employee)-[:HAS_ACCOUNT]->(account)
WHERE NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(c))
RETURN paths
UNION
MATCH paths=(admin:administrator {name:'Liz'})-[:MEMBER_OF]->()-[:ALLOWED_DO_NOT_INHERIT]->()<-[:WORKS_FOR]-(employee)-[:HAS_ACCOUNT]->(account)
RETURN paths
回顾一下,DENIED
的优先级高于 ALLOWED_INHERIT
,但低于 ALLOWED_DO_NOT_INHERIT
。因此,如果管理员通过 ALLOWED_DO_NOT_INHERIT
和 DENIED
连接到公司,则 ALLOWED_DO_NOT_INHERIT
优先。
注意:Cypher 支持 UNION
和 UNION ALL
运算符。UNION
从最终结果集中消除重复结果,而 UNION ALL
包含所有重复项。
查找管理员可以访问的所有资源
让我们朝着图数据库管理员在内省或探索数据库时可能看到的方面迈进一步。每当现场管理员登录系统时,都会显示一个基于浏览器的列表,其中包含他可以管理的所有员工和员工帐户。
让我们看看任何管理员可以访问的所有资源
MATCH paths=(admin:administrator)-[:MEMBER_OF]->()-[:ALLOWED_INHERIT]->()<-[:CHILD_OF*0..3]-(company)<-[:WORKS_FOR]-(employee)-[:HAS_ACCOUNT]->(account)
WHERE NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(company))
RETURN admin.name AS Admin, employee.name AS Employee, collect(account.name) AS Accounts
ORDER BY Admin ASC
UNION
MATCH paths=(admin)-[:MEMBER_OF]->()-[:ALLOWED_DO_NOT_INHERIT]->()<-[:WORKS_FOR]-(employee)-[:HAS_ACCOUNT]->(account)
RETURN admin.name AS Admin, employee.name AS Employee, collect(account.name) AS Accounts
ORDER BY Admin ASC
此查询匹配每个管理员可以访问的所有资源,并考虑了 ALLOWED_INHERIT
、ALLOWED_DO_NOT_INHERIT
和 DENIED
控制之间的交互。
确定管理员是否可以访问某个资源
我们刚刚查看的查询返回了管理员可以管理的员工和帐户列表。在 Web 应用程序中,每个这些资源(员工、帐户)都可以通过其自己的 URI 访问。给定一个友好的 URI(例如,http: //acme/accounts/ 5436),有什么可以阻止管理员意外更改未授权的帐户?
需要一个查询来确定管理员是否可以访问特定资源
MATCH p=(admin:administrator)-[:MEMBER_OF]->()-[:ALLOWED_INHERIT]->()<-[:CHILD_OF*0..3]-(company:company)
WHERE NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(company))
RETURN admin.name AS Admin, collect(company.name) AS Resource
UNION
MATCH p=(admin)-[:MEMBER_OF]->()-[:ALLOWED_DO_NOT_INHERIT]->(company)
RETURN admin.name AS Admin, collect(company.name) AS Resource
查找帐户的管理员
前两个查询表示图的“自顶向下”视图。在本教程的最后一个查询中,我们将讨论数据的“自底向上”视图。给定一个资源——员工或帐户——谁可以管理它?
这是查询
MATCH p=(resource {name:'Acct 10'})-[:WORKS_FOR|HAS_ACCOUNT*1..2]-(company)-[:CHILD_OF*0..3]->()<-[:ALLOWED_INHERIT]-()<-[:MEMBER_OF]-(admin)
WHERE NOT ((admin)-[:MEMBER_OF]->()-[:DENIED]->()<-[:CHILD_OF*0..3]-(company))
RETURN resource.name AS Resource, collect(admin.name) AS Admins
UNION
MATCH p=(resource {name:'Acct 10'})-[:WORKS_FOR|HAS_ACCOUNT*1..2]-(company)<-[:ALLOWED_DO_NOT_INHERIT]-()<-[:MEMBER_OF]-(admin)
RETURN resource.name AS Resource, collect(admin.name) AS Admins
该查询类似于前两个自顶向下的查询,但反过来。请注意 Cypher 如何使用 OR
管道来选择员工或帐户资源。
总结
在 Neo4j 中建模资源图非常自然,因为正在建模的域本质上是一个图。Neo4j 提供快速安全的访问并回答重要问题,例如
-
用户可以访问哪些订阅?用户是否可以访问给定的资源?客户参与了哪些协议?
这些操作的速度和准确性非常关键,因为用户登录系统后无法继续,直到授权计算完成。
Neo4j 为密集连接的权限树提供了亚秒级查询的可能性,从而提高了系统的性能特征。此外,Neo4j 允许在图中忠实地重现客户的结构和内容层次结构,无需修改,从而消除了专门针对特定应用程序的数据复制和反规范化。通过不必专门针对特定应用程序的性能需求来专门化数据,Neo4j 为在其他应用程序中扩展和重用客户图提供了基础。
参考文献
此 GraphGist 具有 Ian Robinson 和 Jim Webber 撰写的 O’Reily“图数据库”书籍中的内容。您可以在 https://www.graphdatabases.com/ 以电子书的形式免费获取。
有益的后续步骤
查看社区管理的开发者资源网站 https://www.neo4j.com/developer
此页面是否有帮助?