快速遍历ACL的策略
我们目前正在开发一个项目,其中主要域对象是内容节点,并且我们正在使用类似 ACL 的系统,其中层次结构中的每个节点都可以包含覆盖或补充其父节点的规则。例如,一切都基于角色和行动。
Node 1 - {Deny All, Allow Role1 View}
\- Node 2 - {Allow Role2 View}
\- Node 3 - {Deny Role1 View}
在这种情况下,规则将按从上到下的顺序读取,因此节点 3 只能由角色 2 看到。它的概念并不复杂。
检索单个节点的规则可能会导致一些查询,获取所有父节点,然后重新创建规则列表并评估它们,但此过程可能很麻烦,因为层次结构可能会变得非常深,并且可能有很多规则每个节点。
我一直在考虑为每个节点准备一张预先计算规则的表,每当权限更改时都可以重新创建该表并将其传播到更新的节点的所有叶节点。
您认为还有其他策略来加速规则的检索和计算吗?理想情况下,它应该在单个查询中完成,但树并不是最好的结构。
We are currently working on a project where the main domain objects are content nodes and we are using an ACL-like system where each node in the hierarchy can contain rules that override or complement those on their parents. Everything is as well based on roles and actions, for example.
Node 1 - {Deny All, Allow Role1 View}
\- Node 2 - {Allow Role2 View}
\- Node 3 - {Deny Role1 View}
In that case, rules will be read in order from top to bottom so the Node 3 can be viewed only by Role2. It's not really complicated in concept.
Retrieving the rules for a single node can result in some queries, getting all the parents and then recreating the list of rules and evaluating them, but this process can be cumbersome because the hierarchy can become quite deep and there may be a lot of rules on each node.
I have been thinking on preparing a table with precalculated rules for each node which could be recreated whenever a permission is changed and propagated to all the leaf nodes of the updated one.
Do you think of any other strategy to speed up the retrieval and calculation of the rules? Ideally it should be done in a single query, but trees are not the best structures for that.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我认为可能会采用 观察者模式。
这个想法是,每个节点维护一个预先计算的列表,并且只需由其父节点通知任何更新,以便它可以重新计算该列表。
这可以通过两种不同的方式完成:
计算我建议如果可能的话使用
1
,因为它不涉及重新计算整个世界当 root 更新时,并且仅在需要时重新计算(实际上是惰性评估),但如果您很少更新但需要极快的检索(尽管存在更多并发问题),您可能更喜欢第二个选项。让我们来说明解决方案 1:
现在,首先,它们都没有预先计算任何内容(都处于脏状态),如果我要求
Node2A
规则:Node2A
实现它是脏的:它查询Node2
规则Node2
意识到它是脏的:它查询Root
Root
没有任何父级,因此它不能是脏的,它将其规则发送到Node2
Node2
缓存来自Root
的答案,将其规则与从Node2 接收到的规则合并code>Root
并清除脏位,它将合并结果(现在已缓存)发送到Node2A
Node2A
缓存、合并、清除脏位并返回结果如果我随后询问
Node2B
规则:Node2B
is dirty,它查询Node2
Node2
is clean,它回复请注意,Node2 没有重新计算任何内容。
在更新情况下:
Node1
:我使用Root
缓存规则重新计算新规则并向Node1A
和发送节拍>Node1B
通知它们的缓存已过时Node1A
和Node1B
设置了脏位,如果它们有子节点,它们也会传播此通知请注意,因为我缓存的
Root
规则 我不必查询Root
对象,如果它是一个足够简单的操作,您可能不希望根本不缓存它们:如果您不这样做在这里进行分布式播放,查询Root
仅涉及内存往返,您可能不希望重复它,以节省一些内存和簿记。希望它能让你继续前进。
I would think that an Observer Pattern might be adapted.
The idea would be that each
Node
maintains a precomputed list and is simply notified by its parent of any update so that it can recompute this list.This can be done in 2 different ways:
I would advise going with
1
if possible, since it does not involve recomputing the whole world when root is updated, and only recomputing when needed (lazy eval in fact) but you might prefer the second option if you update rarely but need blazing fast retrieval (there are more concurrency issues though).Let's illustrate Solution 1:
Now, to begin with, none of them has precomputed anything (there are all in a dirty state), if I ask for
Node2A
rules:Node2A
realizes it is dirty: it queriesNode2
rulesNode2
realizes it is dirty: it queriesRoot
Root
does not have any parent, so it cannot be dirty, it sends its rules toNode2
Node2
caches the answer fromRoot
, merges its rules with those received fromRoot
and cleans the dirty bit, it sends the result of the merge (cached now) toNode2A
Node2A
caches, merges, cleans the dirty bit and returns the resultIf I subsequently asks for
Node2B
rules:Node2B
is dirty, it queriesNode2
Node2
is clean, it repliesNode2B
caches, merges, cleans the dirty bit and returns the resultNote that
Node2
did not recomputed anything.In the update case:
Node1
: I use theRoot
cached rules to recompute the new rules and send a beat toNode1A
andNode1B
to notify them their cache is outdatedNode1A
andNode1B
set their dirty bit, they would also have propagated this notification had they had childrenNote that because I cached
Root
rules I don't have to query theRoot
object, if it's a simple enough operation, you might prefer not to cache them at all: if you're not playing distributed here, and queryingRoot
only involves a memory round-trip you might prefer not to duplicate it in order to save up some memory and book-keeping.Hopes it gets you going.
您的预计算版本似乎存储了与每个节点上的每个角色相关的所有权限。您可以通过遍历树,在到达节点时对节点进行编号,并为每个角色生成节点编号和权限更改的数组(仅针对与该角色相关的权限发生变化的节点)来节省一些时间和空间。 。这会产生仅与输入树(包括其注释)大小成线性关系的输出。然后,当您要检查节点上某个角色的权限时,请使用该节点的编号来搜索数组,以找到数组中代表您在游览期间访问该节点时最近一次权限更改的点。
这可能以某种方式与 http://en.wikipedia.org/wiki/Range_Minimum_Query 和 http://en.wikipedia.org/wiki/Lowest_common_ancestor,但我不真的不知道这些参考资料是否有帮助。
Your version of pre-computation appears to store all the permissions relevant to each role at each node. You can save a little time and space by traversing the tree, numbering the nodes as you reach them, and producing, for each role, an array of the node numbers and permission changes just for the nodes at which the permissions relevant to that role change. This produces output only linear in the size of the input tree (including its annotations). Then when you come to check a permission for a role at a node, use the number of that node to search the array to find the point in the array that represents the most recent change of permission when you visited that node during the tour.
This may be associated in some way with http://en.wikipedia.org/wiki/Range_Minimum_Query and http://en.wikipedia.org/wiki/Lowest_common_ancestor, but I don't really know if those references will help or not.