如何使用 ACL 根据特定用户的权限(例如 EDIT)过滤域对象列表?

2022-01-04 00:00:00 permissions acl php symfony domain-object

在 Web 应用程序中使用 Symfony2 中的 ACL 实现时,我们遇到了一个用例,其中建议的使用 ACL 的方式(检查用户对单个域对象的权限)变得不可行.因此,我们想知道是否存在可以用来解决我们的问题的 ACL API 的某些部分.

When using the ACL implementation in Symfony2 in a web application, we have come across a use case where the suggested way of using the ACLs (checking a users permissions on a single domain object) becomes unfeasible. Thus, we wonder if there exists some part of the ACL API we can use to solve our problem.

用例在一个控制器中,它准备了一个域对象列表以在模板中呈现,以便用户可以选择她想要编辑的对象.用户无权编辑数据库中的所有对象,因此必须相应地过滤列表.

The use case is in a controller that prepares a list of domain objects to be presented in a template, so that the user can choose which of her objects she wants to edit. The user does not have permission to edit all of the objects in the database, so the list must be filtered accordingly.

这可以(以及其他解决方案)根据两种策略来完成:

This could (among other solutions) be done according to two strategies:

1) 一个查询过滤器,将给定的查询附加到当前用户的一个或多个对象的 ACL 中的有效对象 ID.即:

1) A query filter that appends a given query with the valid object ids from the present user's ACL for the object(or objects). I.e:

WHERE <other conditions> AND u.id IN(<list of legal object ids here>)

2) 查询后过滤器,在从数据库中检索到完整列表后,它会删除用户没有正确权限的对象.即:

2) A post-query filter that removes the objects the user does not have the correct permissions for after the complete list has been retrieved from the database. I.e:

$objs   = <query for objects>
$objIds = <getting all the permitted obj ids from the ACL>
for ($obj in $objs) {
    if (in_array($obj.id, $objIds) { $result[] = $obj; } 
}
return $result;

第一种策略更可取,因为数据库正在执行所有过滤工作,并且都需要两次数据库查询.一个用于 ACL,一个用于实际查询,但这可能是不可避免的.

The first strategy is preferable as the database is doing all the filtering work, and both require two database queries. One for the ACLs and one for the actual query, but that is probably unavoidable.

在 Symfony2 中是否有任何这些策略(或达到预期结果)的实现?

Is there any implementation of one of these strategies (or something achieving the desired results) in Symfony2?

推荐答案

假设您有一组要检查的域对象,您可以使用 security.acl.provider 服务的 findAcls() 方法在 isGranted() 调用之前批量加载.

Assuming that you have a collection of domain objects that you want to check, you can use the security.acl.provider service's findAcls() method to batch load in advance of the isGranted() calls.

条件:

数据库中填充了测试实体,对于我的数据库中的随机用户具有 MaskBuilder::MASK_OWNER 的对象权限,以及角色 MASK_VIEW 的类权限IS_AUTHENTICATED_ANONYMOUSLY;MASK_CREATE for ROLE_USER;和 MASK_EDITMASK_DELETE 用于 ROLE_ADMIN.

Database was populated with test entities, with object permissions of MaskBuilder::MASK_OWNER for a random user from my database, and class permissions of MASK_VIEW for role IS_AUTHENTICATED_ANONYMOUSLY; MASK_CREATE for ROLE_USER; and MASK_EDIT and MASK_DELETE for ROLE_ADMIN.

测试代码:

$repo = $this->getDoctrine()->getRepository('FooBundleEntityBar');
$securityContext = $this->get('security.context');
$aclProvider = $this->get('security.acl.provider');

$barCollection = $repo->findAll();

$oids = array();
foreach ($barCollection as $bar) {
    $oid = ObjectIdentity::fromDomainObject($bar);
    $oids[] = $oid;
}

$aclProvider->findAcls($oids); // preload Acls from database

foreach ($barCollection as $bar) {
    if ($securityContext->isGranted('EDIT', $bar)) {
        // permitted
    } else {
        // denied
    }
}

结果:

调用 $aclProvider->findAcls($oids);,分析器显示我的请求包含 3 个数据库查询(作为匿名用户).

With the call to $aclProvider->findAcls($oids);, the profiler shows that my request contained 3 database queries (as anonymous user).

如果没有对 findAcls() 的调用,相同的请求包含 51 个查询.

Without the call to findAcls(), the same request contained 51 queries.

请注意,findAcls() 方法以 30 个批次(每批次 2 个查询)加载,因此您的查询数量会随着数据集的增加而增加.这个测试是在工作日结束时大约 15 分钟内完成的;有机会,我会更彻底地复习和复习相关方法,看看是否还有其他有用的ACL系统用途,并在这里报告.

Note that the findAcls() method loads in batches of 30 (with 2 queries per batch), so your number of queries will go up with larger datasets. This test was done in about 15 minutes at the end of the work day; when I have a chance, I'll go through and review the relevant methods more thoroughly to see if there are any other helpful uses of the ACL system and report back here.

相关文章