我们目前正在开发一个项目,其中主要域对象是内容节点,并且我们正在使用类似 ACL 的系统,其中层次结构中的每个节点都可以包含覆盖或补充其父节点的规则。例如,一切都基于角色和行动。
Node 1 - {Deny All, Allow Role1 View}
\- Node 2 - {Allow Role2 View}
\- Node 3 - {Deny Role1 View}
在这种情况下,规则将按照从上到下的顺序读取,因此节点 3 只能由角色 2 看到。它的概念并不复杂。
检索单个节点的规则可能会导致一些查询,获取所有父节点,然后重新创建规则列表并评估它们,但这个过程可能很麻烦,因为层次结构可能会变得非常深并且可能有很多每个节点上的规则。
我一直在考虑为每个节点准备一个包含预先计算规则的表,每当权限更改时都可以重新创建该表并将其传播到更新后的所有叶节点。
您认为还有其他策略来加速规则的检索和计算吗?理想情况下,它应该在单个查询中完成,但树并不是最好的结构。
最佳答案
我认为 Observer Pattern可能会进行调整。
这个想法是每个Node
维护一个预先计算的列表,并且只需由其父节点通知任何更新,以便它可以重新计算该列表。
这可以通过两种不同的方式完成:
- 通知发生了更改,但不重新计算任何内容
- 每次更新时重新计算
如果可能的话,我建议使用1
,因为它不涉及在更新根时重新计算整个世界,并且仅在需要时重新计算(事实上是惰性评估),但您可能更喜欢第二个如果您很少更新但需要极快的检索(但存在更多并发问题),则可以选择此选项。
让我们举例说明解决方案 1:
Root ___ Node1 ___ Node1A
\ \__ Node1B
\_ Node2 ___ Node2A
\__ Node2B
现在,首先,如果我要求 Node2A
规则,它们都没有预先计算任何东西(它们都处于脏状态):
Node2A
意识到它是脏的:它查询Node2
规则Node2
意识到它是脏的:它查询Root
Root
没有任何父级,因此它不能是脏的,它将其规则发送到Node2
Node2
缓存来自Root
的答案,将其规则与从Root
接收到的规则合并并清除脏位,它发送以下结果合并(现已缓存)到Node2A
Node2A
缓存、合并、清理脏位并返回结果
如果我随后请求 Node2B
规则:
Node2B
是脏的,它查询Node2
Node2
是干净的,它会回复Node2B
缓存、合并、清理脏位并返回结果
请注意,Node2
没有重新计算任何内容。
在更新情况下:
- 我更新
Node1
:我使用Root
缓存规则重新计算新规则并向Node1A
和Node1B 发送节拍
通知他们缓存已过时 Node1A
和Node1B
设置了它们的脏位,如果它们有 child ,它们也会传播此通知
请注意,因为我缓存了 Root
规则,所以我不必查询 Root
对象,如果这是一个足够简单的操作,您可能不希望将它们缓存在all:如果您不在这里玩分布式游戏,并且查询 Root
仅涉及内存往返,您可能不希望重复它,以节省一些内存和簿记。
希望它能让你继续前进。
关于performance - 快速遍历ACL的策略,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2636955/