Как использовать тузы в Symfony2? - PullRequest
11 голосов
/ 07 ноября 2011

У меня проблема с тузами в классе. Я создал туз для класс как это:

$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

Этот метод хорошо адаптирован к проверке разрешений "СОЗДАТЬ", где нет доступного экземпляра объекта для передачи в метод. Тем не мение, должна быть возможность проверить, предоставляется ли другое разрешение на база конкретного экземпляра:

$entity = new Class\FQCN();
$em->persist($entity);
$em->flush();
$securityContext->isGranted('VIEW', $entity);  // returns false

Здесь тест не пройден. Я ожидал, что пользователь, который имеет данный маска разрешения для класса будет иметь одинаковые разрешения для каждого экземпляр этого класса, как указано в документации ( PermissionGrantingStrategy сначала проверяет все ваши ACE объектной области, если ни один из них не применим, проверки ACE на уровне класса будут проверены "), но похоже, дело не в этом.

Ответы [ 4 ]

6 голосов
/ 23 августа 2012

вы все делаете правильно. и согласно нижней части этой страницы , это должно работать, но это не так.

Самый простой способ заставить его работать - создать класс 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's 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 }    
5 голосов
/ 01 ноября 2012

Необходимо убедиться, что каждый объект имеет свой собственный ACL (используйте $aclProvider->createAcl($entity)), чтобы разрешения на уровне класса работали правильно.

Смотрите это обсуждение: https://groups.google.com/forum/?fromgroups=#!topic/symfony2/pGIs0UuYKX4

2 голосов
/ 19 февраля 2012

Если у вас нет существующей сущности, вы можете проверить объектную идентичность, которую вы создали. Будьте осторожны, чтобы использовать «двойной обратный слеш» из-за экранирования обратного слеша.

<code>$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("
"); } еще { бросить новый AccessDeniedException (); }

Это должно работать!

Если бы вы проверяли «объектную область», вы могли бы просто использовать $ post вместо $ objectIdentity в вызове функции isGranted.

0 голосов
/ 27 января 2014

Я попытался найти лучшее решение для этой проблемы, и я думаю, что лучший ответ - тот, что написал Барт.Я просто хочу расширить решение.

Допустим, вы хотите предоставить доступ к определенному типу объекта для конкретного пользователя, но не для конкретного экземпляра объекта (например, 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.

...