如何使用 Symfony ACL 过滤我的 Doctrine 查询

Posted

技术标签:

【中文标题】如何使用 Symfony ACL 过滤我的 Doctrine 查询【英文标题】:How to filter my Doctrine queries with Symfony ACL 【发布时间】:2013-02-13 16:49:39 【问题描述】:

Symfony ACL 允许我授予对实体的访问权限,然后对其进行检查:

if (false === $securityContext->isGranted('EDIT', $comment)) 
    throw new AccessDeniedException();

但是,如果我在数据库中有数千个实体,而用户只能访问其中的 10 个,我不想将所有实体加载到内存中并进行水合。

如何在仅过滤用户有权访问的实体(在 SQL 级别)时执行简单的“SELECT * FROM X”?

【问题讨论】:

你试过createQuery方法吗? 你看过这个 SO 答案了吗? ***.com/questions/9652755/… 【参考方案1】:

就是这样:不可能

去年我一直在研究一种替代 ACL 系统,该系统允许直接在数据库查询中进行过滤。

我公司最近同意开源,所以这里是:http://myclabs.github.io/ACL/

【讨论】:

有一个解决方法。可以列出 SecurityIdentity 和 UserSecurityIdentity 的 ACE,然后将 WHERE 子句注入查询而不加入,只需 id。 是的,但这是一个像 WHERE id IN (1, 2, 3, …) 这样的查询,它(当给定许多 id 时)效率很低 :( 但你是对的,值得一提。此外,这将是 2 个 DB 查询而不是一个(带有 JOIN)。 不正确,WHERE IN () 应该很快 - dev.mysql.com/doc/refman/5.0/en/… 。此外,ID 数量的限制取决于允许的查询数据包大小,默认情况下为 16MB(可增加到 1GB),足以满足查询中至少 100 万个 IDS(我认为)。查询的数量取决于您存储 ACL 规则的位置 - 可能在文件或内存缓存中 - 所以 1 个查询一起。 在我的工作中,大多数以这种方式完成的过滤最终会在WHERE … IN (…) 子句中产生 1,000 到 10,000 个 ID(在可能包含数百万行的表中)。这不好。我同意这不是数据量少的问题。 @galeaspablo 正如我所说的,问题是如果您的列表包含 1,000、10,000 甚至 1M ID... 将您的 log(n) 乘以它。而且我不确定执行第一个查询以获取 1M ID,然后在 IN 子句中使用 1M ID 进行另一个查询是否有效(甚至是否可行)。【参考方案2】:

正如@gregor 在之前的讨论中指出的那样,

在您的第一个查询中,获取用户有权访问的所有 object_identity_id(针对特定实体/类 X)的列表(带有自定义查询)。

然后,在查询实体/类 X 的对象列表时,将“IN (object_identity_ids)”添加到您的查询中

Matthieu,我对回答更多猜想并不满意(因为我的猜想对谈话没有任何价值)。所以我对这种方法做了一些基准测试(Digital Ocean 5$/mo VPS)。

正如预期的那样,在使用 IN 数组方法时,表大小并不重要。但是大数组确实会让事情失控。

那么,Join approachIN array approach

当数组大小很大时,JOIN 确实更好。但是,这是假设我们不应该考虑表格大小。事实证明,实际上 IN 数组更快 - 除非有一个大的对象表并且 acl 条目几乎涵盖了每个对象(请参阅链接的问题)。

我在一个单独的问题上扩展了我的推理。请看When using Symfony's ACL, is it better to use a JOIN query or an IN array query?

【讨论】:

【参考方案3】:

您可以查看Doctrine filters。这样您就可以扩展所有查询。我还没有这样做,并且记录了一些限制。但也许它对你有帮助。您将找到 ACL 数据库表 here 的描述。

更新

每个过滤器都会返回一个字符串,所有这些字符串都会被添加到 SQL 查询中,如下所示:

SELECT ... FROM ... WHERE ... AND (<result of filter 1> AND <result of filter 2> ...)

表别名也被传递给过滤器方法。所以我认为你可以在这里添加子查询来过滤你的实体。

【讨论】:

谢谢你的回答,我没看到。 Doctrine 过滤器没有帮助,因为它们不允许加入表,它们只允许在 WHERE 子句中添加 SQL。

以上是关于如何使用 Symfony ACL 过滤我的 Doctrine 查询的主要内容,如果未能解决你的问题,请参考以下文章

Symfony2 ACL 问题

Symfony 2 acl isFieldGranted 抛出异常

Symfony2 ACL 结合另一个条件

如何通过伪造登录来测试 Symfony 2 中的 ACL

Symfony2:如何获取标记有“编辑”ACL 权限的一种类型的所有实体?

为啥 Symfony2 ACL 使用用户名而不是 ID?