Symfony 2 acl isFieldGranted 抛出异常

Posted

技术标签:

【中文标题】Symfony 2 acl isFieldGranted 抛出异常【英文标题】:Symfony 2 acl isFieldGranted throws exception 【发布时间】:2013-10-15 16:44:51 【问题描述】:

我正忙于在我的应用程序中实现类 + 字段 (classFieldAce) 级别的 ACL。一切似乎都运行良好,但我从 ACL 的 isFieldGranted() 方法中得到了意外的行为。这是我的代码:

// setup ACL
$className       = 'Acme\Model\Junk';
$oid             = new ObjectIdentity('class', $className);

try 
    $acl  = $aclProvider->findAcl($oid);
 catch (Exception $e) 
    $acl  = $aclProvider->createAcl($oid);

    $roleUser  = new RoleSecurityIdentity('ROLE_USER');
    $mask      = new MaskBuilder(4); // 4 = EDIT

    $acl->insertclassFieldAce('name', $roleUser, $mask->get());


$aclProvider->updateAcl($acl);

到目前为止一切顺利。我将角色“ROLE_USER”分配给我的用户。现在我想运行一些检查(在我创建服务时手动)。这是检查代码(目前在控制器内部):

// check the ACL
$className       = 'Acme\Model\Junk';
$oid             = new ObjectIdentity('class', $className);
$aclProvider     = $this->get('security.acl.provider');

try 
    $acl             = $aclProvider->findAcl($oid);
 catch (...)

一切都好。现在我要检查的东西:

$sids = array();
foreach ($this->getUser()->getRoles() as $role) 
    $sids[] = new RoleSecurityIdentity($role);

$masks = array();
$masks[] = MaskBuilder::MASK_EDIT;

if ($acl->isFieldGranted('name', $masks, $sids)) 
    echo "OK";
 else 
    echo "NOT ALLOWED";

此时一切正常,我得到输出“OK”。我唯一不确定的是将 $sids 发送到支票的非常迂回的方式 - 所以我的第一个问题是除了手动构建列表之外是否有更快的方式。

当我尝试检查更高的掩码时,事情开始出现“错误”(如意料之外):

$sids = array();
foreach ($this->getUser()->getRoles() as $role) 
    $sids[] = new RoleSecurityIdentity($role);

$masks = array();
$masks[] = MaskBuilder::MASK_OWNER;

if ($acl->isFieldGranted('name', $masks, $sids)) 
    echo "OK";
 else 
    echo "NOT ALLOWED";

$acl->isFieldGranted 不是返回 false,而是抛出 NoAceFoundException。

我是否以错误的方式进行现场检查,还是应该在这里捕获异常?

更新:添加日志:

校验码改为:

    $this->get('logger')->debug('XX: ACL retrieved, checking field grants');
    try 
        if ($acl->isFieldGranted('name', $masks, $sids, true)) 
            $this->get('logger')->debug('XX: ACL OK for field :name:');
        
     catch (NoAceFoundException $e) 
        $this->get('logger')->debug('XX: ACL NOT OK for field :name: NoAceFoundException thrown');
    

检查成功后,日志如下:

DEBUG - SELECT o.id as acl_id, o.object_identifier, o.parent_object_identity_id, 
o.entries_inheriting, c.class_type, e.id as ace_id, e.object_identity_id, e.field_name, 
e.ace_order, e.mask, e.granting, e.granting_strategy, e.audit_success, e.audit_failure, 
s.username, s.identifier as security_identifier FROM acl_object_identities o INNER JOIN 
acl_classes c ON c.id = o.class_id LEFT JOIN acl_entries e ON ( e.class_id = o.class_id AND 
(e.object_identity_id = o.id OR e.object_identity_id IS NULL) ) 
LEFT JOIN acl_security_identities s ON ( s.id = e.security_identity_id ) WHERE (o.id =16)

DEBUG - SELECT t0.name AS name1, t0.roles AS roles2, t0.id AS id3 FROM staff_group t0 
INNER JOIN rel_staff_staff_group ON t0.id = rel_staff_staff_group.group_id 
WHERE rel_staff_staff_group.staff_id = ?  Context: ["242"]

DEBUG - XX: ACL retrieved, checking field grants

DEBUG - XX: ACL OK for field :name:

检查失败时,唯一的变化是这一行(我比较了两个浏览器标签中的日志)

DEBUG - XX: ACL NOT OK for field :name: NoAceFoundException thrown

在日志记录方面没有区别

$acl->isFieldGranted('name', $masks, $sids)

$acl->isFieldGranted('name', $masks, $sids, true)

更新 2:

我在 Symfony 中打开了一个错误报告并已解决 https://github.com/symfony/symfony/issues/9433

【问题讨论】:

@freetrace 感谢您的建议;更新的问题,但没有从日志中得到太多 好的。尝试在您的 $acl->isFieldGranted('name', $masks, $sids) 之前插入此 var_dump($acl->getClassFieldAces('name')); 给你pastebin.com/RPddrX4P。 会不会是ACL系统的bug? 确实是个bug,我更新了问题 【参考方案1】:

看来您必须在代码中捕获NoAceFoundException 并抛出AccessDeniedException

try
    if (!$acl->isFieldGranted('name', $masks, $sids)) 
        throw new Symfony\Component\Security\Core\Exception\AccessDeniedException();
     
 catch (NoAceFoundException $e) 
    throw new Symfony\Component\Security\Core\Exception\AccessDeniedException();

因为:

第一个适用的 ACE 将做出最终决定 权限/身份组合。如果它正在授予,此方法将 返回true,如果是deny,方法会继续检查 下一个权限/身份组合。重复这个过程 直到找到授权 ACE,或者没有权限/身份 留下组合。最后,我们要么抛出一个 NoAceFoundException,或拒绝访问。

所以如果MaskBuilder::MASK_OWNER/RoleSecurityIdentity($role) 组合没有找到NoAceFoundException 将被抛出。详情见this第137行。

【讨论】:

感谢您的研究。老实说,我觉得这很奇怪,因为检查布尔值 TRUE/FALSE 比 TRY/CATCH 块要快得多。 @mogoman 我同意你的看法。这很奇怪,我不明白他们为什么抛出异常而不是简单的 FALSE。

以上是关于Symfony 2 acl isFieldGranted 抛出异常的主要内容,如果未能解决你的问题,请参考以下文章

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

symfony2 选民或 acl

Symfony2 ACL 结合另一个条件

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

Symfony2 ACL 问题

如何在 Symfony2 中制作高级 ACL?