Symfony2 ACL可以相对轻松地按ObjectIdentity
搜索ACE记录,可选择按SecurityIdentity
进行过滤。
但是,我需要反过来:我需要获取给定SecurityIdentity
的所有ACE,可选择按ObjectIdentity
过滤。
我将如何做到这一点?
答案 0 :(得分:3)
这是我最终提出的解决方案。
它有一些重大限制:
另请注意,此方法返回 ObjectIdentities ,而不是 ACE 。从技术上讲,这不是我在我的OP中所要求的,但它足够接近,我认为无论如何我都会发布它。
namespace Acme\DemoBundle\Security\Authorization\Acl;
use Doctrine\DBAL\Connection;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Dbal\MutableAclProvider;
class AclProvider
extends MutableAclProvider
{
/** @var Connection */
protected $connection;
/** Locates all objects that the specified User has access to.
*
* Note that this method has a few limitations:
* - No support for filtering by mask.
* - No support for ACEs that match one of the User's roles (only ACEs that
* reference the User's security identity will be matched).
* - Every ACE that matches is assumed to grant access.
*
* @param UserInterface $user
* @param string $type If set, filter by object type (classname).
*
* @return ObjectIdentity[]
*/
public function findObjectIdentitiesForUser(UserInterface $user, $type=null)
{
$securityIdentity = UserSecurityIdentity::fromAccount($user);
$identifier = sprintf(
'%s-%s'
, $securityIdentity->getClass()
, $securityIdentity->getUsername()
);
$sql = <<<END
SELECT
o.object_identifier
, c.class_type
FROM
{$this->options['sid_table_name']} s
LEFT JOIN
{$this->options['entry_table_name']} e
ON (
(e.security_identity_id = s.id)
or {$this->connection->getDatabasePlatform()->getIsNullExpression('e.security_identity_id')}
)
LEFT JOIN
{$this->options['oid_table_name']} o
ON (o.id = e.object_identity_id)
LEFT JOIN
{$this->options['class_table_name']} c
ON (c.id = o.class_id)
WHERE
s.identifier = {$this->connection->quote($identifier)}
END;
if($type)
{
$sql .= <<<END
AND c.class_type = {$this->connection->quote($type)}
END;
}
$objectIdentities = array();
/* @kludge It would be awesome if we could use hydrateObjectIdentities()
* here. Then we could do super fancy stuff like filter by mask and
* check whether ACEs grant or deny access.
*
* Unfortunately, that method is not accessible to subclasses.
*/
foreach($this->connection->executeQuery($sql)->fetchAll() as $row)
{
$objectIdentities[] = new ObjectIdentity(
$row['object_identifier']
, $row['class_type']
);
}
return $objectIdentities;
}
您还需要通过在捆绑包的services.yml
文件中添加以下内容来覆盖服务容器中的ACL提供程序:
parameters:
security.acl.dbal.provider.class:
Acme\DemoBundle\Security\Authorization\Acl\AclProvider
然后你可以调用这个方法,例如,在这样的控制器中:
use Acme\DemoBundle\Security\Authorization\Acl\AclProvider;
/** @var AclProvider $aclProvider */
$aclProvider = $this->get('security.acl.provider');
$objectIdentities = $aclProvider->findObjectIdentitiesForUser($user, $type);