Новое в Symfony 2.6: Простые Security Voters

Security Voters обеспечивают механизм для настройки мелких ограничений в приложениях Symfony. Основное преимущество перед ACL, является то, что они на порядок проще настраеваемы, настроил и используешь.

В предыдущих версиях Symfony, вотеры реализовал интерфейс VoterInterface, который имел следующую форму:

interface VoterInterface
{
    public function supportsAttribute($attribute);
    public function supportsClass($class);
    public function vote(TokenInterface $token, $object, array $attributes);
}

Реализация этого интерфейса довольно простая, но в результате код получается, как правило, немного раздутой, это можно продемонстрировать следующими 83 строками кода, необходимого для определения простого вотера:

// src/Acme/DemoBundle/Security/Authorization/Voter/PostVoter.php
namespace Acme\DemoBundle\Security\Authorization\Voter;

use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class PostVoter implements VoterInterface
{
    const VIEW = 'view';
    const EDIT = 'edit';

    public function supportsAttribute($attribute)
    {
        return in_array($attribute, array(
            self::VIEW,
            self::EDIT,
        ));
    }

    public function supportsClass($class)
    {
        $supportedClass = 'Acme\DemoBundle\Entity\Post';

        return $supportedClass === $class || is_subclass_of($class, $supportedClass);
    }

    /**
     * @var \Acme\DemoBundle\Entity\Post $post
     */
    public function vote(TokenInterface $token, $post, array $attributes)
    {
        // check if class of this object is supported by this voter
        if (!$this->supportsClass(get_class($post))) {
            return VoterInterface::ACCESS_ABSTAIN;
        }

        // check if the voter is used correct, only allow one attribute
        // this isn't a requirement, it's just one easy way for you to
        // design your voter
        if(1 !== count($attributes)) {
            throw new \InvalidArgumentException(
                'Only one attribute is allowed for VIEW or EDIT'
            );
        }

        // set the attribute to check against
        $attribute = $attributes[0];

        // check if the given attribute is covered by this voter
        if (!$this->supportsAttribute($attribute)) {
            return VoterInterface::ACCESS_ABSTAIN;
        }

        // get current logged in user
        $user = $token->getUser();

        // make sure there is a user object (i.e. that the user is logged in)
        if (!$user instanceof UserInterface) {
            return VoterInterface::ACCESS_DENIED;
        }

        switch($attribute) {
            case self::VIEW:
                // the data object could have for example a method isPrivate()
                // which checks the Boolean attribute $private
                if (!$post->isPrivate()) {
                    return VoterInterface::ACCESS_GRANTED;
                }
                break;

            case self::EDIT:
                // we assume that our data object has a method getOwner() to
                // get the current owner user entity for this data object
                if ($user->getId() === $post->getOwner()->getId()) {
                    return VoterInterface::ACCESS_GRANTED;
                }
                break;
        }

        return VoterInterface::ACCESS_DENIED;
    }
}

В результате этой Symfony DX initiative, Symfony 2.6 позволит определить более простые security voters. Чтобы сделать это, используйте новый класс AbstractVoter который реализует VoterInterface и определяет следующие методы:

abstract class AbstractVoter implements VoterInterface
{
    public function supportsAttribute($attribute);
    public function supportsClass($class);
    public function vote(TokenInterface $token, $object, array $attributes);
    abstract protected function getSupportedClasses();
    abstract protected function getSupportedAttributes();
    abstract protected function isGranted($attribute, $object, $user = null);
}

Три метода supportsAttribute (), supportsClass () и vote() помогут вам уменьшить шаблонный код вотера и позволить вам сосредоточиться на конкретной бизнес-логике приложения. В результате избиратель, как показано выше, теперь занимает только 41 строку кода:

// src/Acme/DemoBundle/Security/Authorization/Voter/PostVoter.php
namespace Acme\DemoBundle\Security\Authorization\Voter;

use Symfony\Component\Security\Core\Authorization\Voter\AbstractVoter;
use Symfony\Component\Security\Core\User\UserInterface;

class PostVoter extends AbstractVoter
{
    const VIEW = 'view';
    const EDIT = 'edit';

    protected function getSupportedAttributes()
    {
        return array(self::VIEW, self::EDIT);
    }

    protected function getSupportedClasses()
    {
        return array('Acme\DemoBundle\Entity\Post');
    }

    protected function isGranted($attribute, $post, $user = null)
    {
        // make sure there is a user object (i.e. that the user is logged in)
        if (!$user instanceof UserInterface) {
            return false;
        }

        // custom business logic to decide if the given user can view
        // and/or edit the given post
        if ($attribute == self::VIEW && !$post->isPrivate()) {
            return true;
        }

        if ($attribute == self::EDIT && $user->getId() === $post->getOwner()->getId()) {
            return true;
        }

        return false;
    }
}

Писать меньше кода чтобы получить те же результаты, это способ повысить вашу производительность. Это наша цель с момента введения DX initiative, и Symfony 2.6 будет первая версия реализовывающая этот новый философию.

Источник: http://symfony.com/blog/new-in-symfony-2-6-simpler-security-voters

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

8 + четырнадцать =