Метод vote класса Voter
Метод vote класса Voter является центральным
элементом системы авторизации Symfony. Он вызывается
менеджером решений AccessDecisionManager для
вычисления итогового результата голосования всех
зарегистрированных voter-ов. Метод принимает объект
токена $token, произвольный атрибут
$attribute и субъект доступа $subject.
Возвращает одна из трёх констант: ACCESS_GRANTED,
ACCESS_DENIED или ACCESS_ABSTAIN.
Синтаксис
public function vote(TokenInterface $token, mixed $subject, array $attributes): int
Пример
Давайте создадим собственный voter, который разрешает
доступ к объекту Article только его автору.
Для начала создадим сущность:
<?php
namespace AppEntity;
use DoctrineORMMapping as ORM;
#[ORMEntity]
class Article
{
#[ORMId, ORMGeneratedValue, ORMColumn(type: 'integer')]
private ?int $id = null;
#[ORMColumn(type: 'string', length: 255)]
private string $title = '';
#[ORMColumn(type: 'text')]
private string $text = '';
#[ORMManyToOne(targetEntity: User::class)]
private ?User $author = null;
public function getId(): ?int
{
return $this->id;
}
public function getTitle(): string
{
return $this->title;
}
public function setTitle(string $title): self
{
$this->title = $title;
return $this;
}
public function getText(): string
{
return $this->text;
}
public function setText(string $text): self
{
$this->text = $text;
return $this;
}
public function getAuthor(): ?User
{
return $this->author;
}
public function setAuthor(?User $author): self
{
$this->author = $author;
return $this;
}
}
?>
Теперь создадим voter, который в методе vote
проверяет, является ли текущий пользователь автором
статьи:
<?php
namespace AppSecurity;
use AppEntityArticle;
use AppEntityUser;
use SymfonyComponentSecurityCoreAuthenticationTokenTokenInterface;
use SymfonyComponentSecurityCoreAuthorizationVoterVoter;
class ArticleVoter extends Voter
{
public const EDIT = 'ARTICLE_EDIT';
public const VIEW = 'ARTICLE_VIEW';
protected function supports(string $attribute, mixed $subject): bool
{
if (!in_array($attribute, [self::EDIT, self::VIEW])) {
return false;
}
if (!$subject instanceof Article) {
return false;
}
return true;
}
protected function voteOnAttribute(string $attribute, mixed $subject, TokenInterface $token): bool
{
$user = $token->getUser();
if (!$user instanceof User) {
return false;
}
/** @var Article $article */
$article = $subject;
return $user === $article->getAuthor();
}
}
?>
Теперь используем метод vote напрямую для проверки
доступа к статье:
<?php
namespace AppController;
use AppEntityArticle;
use AppEntityUser;
use AppSecurityArticleVoter;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentSecurityCoreAuthenticationTokenUsernamePasswordToken;
use SymfonyComponentRoutingAttributeRoute;
class ArticleController extends AbstractController
{
#[Route('/article/{id}', name: 'article_show')]
public function show(Article $article): Response
{
$voter = new ArticleVoter();
$user = new User();
$user->setLogin('abcde');
$article->setAuthor($user);
$token = new UsernamePasswordToken($user, 'main', $user->getRoles());
$res = $voter->vote($token, $article, [ArticleVoter::VIEW]);
return new Response((string) $res);
}
}
?>
Результат выполнения кода при совпадении автора:
"1"
Пример
Давайте проверим, что вернёт метод vote, если
текущий пользователь не является автором статьи:
<?php
namespace AppController;
use AppEntityArticle;
use AppEntityUser;
use AppSecurityArticleVoter;
use SymfonyBundleFrameworkBundleControllerAbstractController;
use SymfonyComponentHttpFoundationResponse;
use SymfonyComponentSecurityCoreAuthenticationTokenUsernamePasswordToken;
use SymfonyComponentRoutingAttributeRoute;
class ArticleController extends AbstractController
{
#[Route('/article/check', name: 'article_check')]
public function check(): Response
{
$voter = new ArticleVoter();
$author = new User();
$author->setLogin('abcde');
$other = new User();
$other->setLogin('user');
$article = new Article();
$article->setTitle('article');
$article->setAuthor($author);
$token = new UsernamePasswordToken($other, 'main', $other->getRoles());
$res = $voter->vote($token, $article, [ArticleVoter::EDIT]);
return new Response((string) $res);
}
}
?>
Результат выполнения кода при несовпадении автора:
"-1"
Смотрите также
-
класс
Voter,
который лежит в основе системы голосования -
метод
supports,
который определяет, поддерживает ли voter атрибут -
метод
voteOnAttribute,
который содержит логику проверки доступа -
атрибут
IsGranted,
который использует voter для проверки прав