Как использовать тузы класса в Symfony2?
У меня проблема с тузами класса. Я создал туза для
класс следующим образом:
$userIdentity = UserSecurityIdentity::fromAccount($user);
$classIdentity = new ObjectIdentity('some_identifier', 'Class\FQCN');
$acl = $aclProvider->createAcl($classIdentity);
$acl->insertClassAce($userIdentity, MaskBuilder::MASK_CREATE);
$aclProvider->updateAcl($acl);
Теперь я пытаюсь проверить права пользователя. Я нашел этот путь
делать вещи, которые не документированы, но дает ожидаемые
результаты на основе класса:
$securityContext->isGranted('CREATE', $classIdentity); // returns true
$securityContext->isGranted('VIEW', $classIdentity); // returns true
$securityContext->isGranted('DELETE', $classIdentity); // returns false
Этот метод хорошо адаптирован к проверке разрешений "CREATE", где
нет доступного экземпляра объекта для перехода к методу. Однако,
должно быть возможно проверить, предоставлено ли другое разрешение на
конкретный экземпляр:
$entity = new Class\FQCN();
$em->persist($entity);
$em->flush();
$securityContext->isGranted('VIEW', $entity); // returns false
В этом случае сбой теста. Я ожидал, что пользователь, у которого есть
маска разрешения для класса будет иметь одинаковые разрешения для каждого
экземпляр этого класса, как указано в документации ("The
PermissionGrantingStrategy сначала проверяет все ваши ACE-объекты, если
ни один не применим, будут проверены ACE класса. "), но это
похоже, не здесь.
Ответы
Ответ 1
вы делаете это правильно. и в соответствии с нижней частью эта страница, она должна работать, но это не так.
Самый простой способ заставить его работать - создать класс AclVoter:
namespace Core\Security\Acl\Voter;
use JMS\SecurityExtraBundle\Security\Acl\Voter\AclVoter as BaseAclVoter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Doctrine\Common\Util\ClassUtils;
class AclVoter extends BaseAclVoter
{
public function vote( TokenInterface $token , $object , array $attributes )
{
//vote for object first
$objectVote = parent::vote( $token , $object , $attributes );
if( self::ACCESS_GRANTED === $objectVote )
{
return self::ACCESS_GRANTED;
}
else
{
//then for object class
$oid = new ObjectIdentity( 'class' , ClassUtils::getRealClass( get_class( $object ) ) );
$classVote = parent::vote( $token , $oid , $attributes );
if( self::ACCESS_ABSTAIN === $objectVote )
{
if( self::ACCESS_ABSTAIN === $classVote )
{
return self::ACCESS_ABSTAIN;
}
else
{
return $classVote;
}
}
else if( self::ACCESS_DENIED === $objectVote )
{
if( self::ACCESS_ABSTAIN === $classVote )
{
return self::ACCESS_DENIED;
}
else
{
return $classVote;
}
}
}
return self::ACCESS_ABSTAIN;
}
}
то в security.yml установите это:
jms_security_extra:
voters:
disable_acl: true
и, наконец, настроить избирателя как услугу:
core.security.acl.voter.basic_permissions:
class: Core\Security\Acl\Voter\AclVoter
public: false
arguments:
- '@security.acl.provider'
- '@security.acl.object_identity_retrieval_strategy'
- '@security.acl.security_identity_retrieval_strategy'
- '@security.acl.permission.map'
- '@?logger'
tags:
- { name: security.voter , priority: 255 }
- { name: monolog.logger , channel: security }
Ответ 2
Вам необходимо убедиться, что для каждого объекта есть свой ACL (используйте $aclProvider->createAcl($entity)
) для прав доступа к классу.
Смотрите это обсуждение: https://groups.google.com/forum/?fromgroups=#!topic/symfony2/pGIs0UuYKX4
Ответ 3
Если у вас нет существующего объекта, вы можете проверить его на созданном объекте.
Будьте осторожны, чтобы использовать "двойную обратную косую черту" из-за выхода из обратной косой черты.
$post = $postRepository->findOneBy(array('id' => 1));
$securityContext = $this->get('security.context');
$objectIdentity = new ObjectIdentity('class', 'Liip\\TestBundle\\Entity\\Post');
// check for edit access
if (true === $securityContext->isGranted('EDIT', $objectIdentity)) {
echo "Edit Access granted to: <br/><br/> ";
print_r("<pre>");
print_r($post);
print_r("</pre>");
} else {
throw new AccessDeniedException();
}
Это должно сработать!
Если вы хотите проверить "область объекта", вы можете просто использовать $post вместо $objectIdentity в вызове функции isGranted.
Ответ 4
Я попытался найти лучшее решение для этой проблемы, и я думаю, что лучший ответ - это ретривер/отредактированный Бартом. Я просто хочу расширить решение.
Предположим, вы хотите предоставить доступ к определенному типу объекта для определенного пользователя, но не для конкретного экземпляра объекта (например, id = 1).
Затем вы можете сделать следующее:
$aclProvider = $this->get('security.acl.provider');
$objectIdentity = new ObjectIdentity('class', 'someNamspace\\SeperatedByDoubleSlashes');
$acl = $aclProvider->createAcl($objectIdentity);
// retrieving the security identity of the currently logged-in user
$securityContext = $this->get('security.context');
$user = $securityContext->getToken()->getUser();
$securityIdentity = UserSecurityIdentity::fromAccount($user);
// grant owner access
$acl->insertObjectAce($securityIdentity, MaskBuilder::MASK_OWNER);
$aclProvider->updateAcl($acl);
$securityContext = $this->get('security.context');
// check for edit access
if (false === $securityContext->isGranted('EDIT', $objectIdentity)) {
throw new AccessDeniedException();
}
Разница с примером, приведенным в поваренной книге Symfony, заключается в том, что вы используете область класса, а не область объекта.
Там только 1 строка, которая делает разницу:
$objectIdentity = new ObjectIdentity('class', 'someNamspace\\SeperatedByDoubleSlashes');
вместо:
$objectIdentity = ObjectIdentity::fromDomainObject($object);
Вы все равно можете добавлять определенные разрешения для конкретных экземпляров объектов, если у вас есть хотя бы одно разрешение класса в классах acl.