快速遍历ACL的策略

发布于 2024-08-29 00:53:31 字数 499 浏览 2 评论 0原文

我们目前正在开发一个项目,其中主要域对象是内容节点,并且我们正在使用类似 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

甜警司 2024-09-05 00:53:32

我认为可能会采用 观察者模式

这个想法是,每个节点维护一个预先计算的列表,并且只需由其父节点通知任何更新,以便它可以重新计算该列表。

这可以通过两种不同的方式完成:

  1. 通知发生了更改,但不要重新计算任何内容
  2. 在每次更新时重新

计算我建议如果可能的话使用 1,因为它不涉及重新计算整个世界当 root 更新时,并且仅在需要时重新计算(实际上是惰性评估),但如果您很少更新但需要极快的检索(尽管存在更多并发问题),您可能更喜欢第二个选项。

让我们来说明解决方案 1:

Root ___ Node1 ___ Node1A
     \         \__ Node1B
      \_ Node2 ___ Node2A
               \__ Node2B

现在,首先,它们都没有预先计算任何内容(都处于脏状态),如果我要求 Node2A 规则:

  • Node2A 实现它是脏的:它查询 Node2 规则
  • Node2 意识到它是脏的:它查询 Root
  • Root 没有任何父级,因此它不能是脏的,它将其规则发送到 Node2
  • Node2 缓存来自 Root 的答案,将其规则与从 Node2 接收到的规则合并code>Root 并清除脏位,它将合并结果(现在已缓存)发送到 Node2A
  • Node2A 缓存、合并、清除脏位并返回结果

如果我随后询问 Node2B 规则:

  • Node2B is dirty,它查询 Node2
  • Node2 is clean,它回复
  • Node2B 缓存、合并、清除脏位并返回结果。

请注意,Node2 没有重新计算任何内容。

在更新情况下:

  • 我更新 Node1:我使用 Root 缓存规则重新计算新规则并向 Node1A发送节拍>Node1B 通知它们的缓存已过时
  • Node1ANode1B 设置了脏位,如果它们有子节点,它们也会传播此通知

请注意,因为我缓存的 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:

  1. notify that a change occurred, but don't recompute anything
  2. recompute at each update

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:

Root ___ Node1 ___ Node1A
     \         \__ Node1B
      \_ Node2 ___ Node2A
               \__ Node2B

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 queries Node2 rules
  • Node2 realizes it is dirty: it queries Root
  • Root does not have any parent, so it cannot be dirty, it sends its rules to Node2
  • Node2 caches the answer from Root, merges its rules with those received from Root and cleans the dirty bit, it sends the result of the merge (cached now) to Node2A
  • Node2A caches, merges, cleans the dirty bit and returns the result

If I subsequently asks for Node2B rules:

  • Node2B is dirty, it queries Node2
  • Node2 is clean, it replies
  • Node2B caches, merges, cleans the dirty bit and returns the result

Note that Node2 did not recomputed anything.

In the update case:

  • I update Node1: I use the Root cached rules to recompute the new rules and send a beat to Node1A and Node1B to notify them their cache is outdated
  • Node1A and Node1B set their dirty bit, they would also have propagated this notification had they had children

Note that because I cached Root rules I don't have to query the Root 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 querying Root 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.

心房敞 2024-09-05 00:53:32

您的预计算版本似乎存储了与每个节点上的每个角色相关的所有权限。您可以通过遍历树,在到达节点时对节点进行编号,并为每个角色生成节点编号和权限更改的数组(仅针对与该角色相关的权限发生变化的节点)来节省一些时间和空间。 。这会产生仅与输入树(包括其注释)大小成线性关系的输出。然后,当您要检查节点上某个角色的权限时,请使用该节点的编号来搜索数组,以找到数组中代表您在游览期间访问该节点时最近一次权限更改的点。

这可能以某种方式与 http://en.wikipedia.org/wiki/Range_Minimum_Queryhttp://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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文