Я почти у цели.
Есть таблица User, таблица Role, таблица user_role для связи many-to-many юзеров и ролей.
Модель юзеров предоставляет метод getRoles() и
реализует UserInterfacenamespace AppBundle\Entity;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;
class User implements UserInterface
{
// ...
/**
* @var \Doctrine\Common\Collections\Collection
*/
private $userRoles;
/**
* Constructor
*/
public function __construct()
{
$this->userRoles = new \Doctrine\Common\Collections\ArrayCollection();
}
/**
* Get userRoles
*
* @return \Doctrine\Common\Collections\Collection
*/
public function getUserRoles()
{
return $this->userRoles;
}
/**
* Геттер для массива ролей.
*
* @return array An array of Role objects
*/
public function getRoles()
{
return $this->getUserRoles()->map(function ($item) {
return $item->getName();
})->toArray();
}
/**
* @param $roleName
*
* @return bool
*/
public function hasRole($roleName)
{
return in_array($roleName, $this->getRoles());
}
}
Я узнал, что загружать роли в UsernamePasswordToken можно с помощью
re-authenticate the userПереопределение токена юзера:$tokenStorage = $this->get('security.token_storage');
/** @var $user User */
$user = $tokenStorage->getToken()->getUser();
$token = new UsernamePasswordToken(
$user,
null,
'main',
$user->getRoles()
);
$this->get('security.token_storage')->setToken($token);
Если не переопределить токен, $token->getRoles() выдаст лишь роль ROLE_ADMIN (не понимаю откуда она берется, предположительно, это сам симфони присваивает её по дефолту в режиме DEV). А после переопределения, $token->getRoles() выдаёт все роли из БД, доступные юзеру. Что даёт нам возможность в voter-ах делать так:
protected function voteOnAttribute($attribute, $subject, TokenInterface $token)
{
// ...
if ($this->decisionManager->decide($token, array('ROLE_DB_SUPER_ADMIN'))) {
return true;
}
// ...
}
Так вот, вопрос, где лучше в Simfony3 сделать переопределение токена (см. код выше)? Это нормальная практика? Как я понимаю, делать это переопределение лучше навесив какой-нибудь kernel-listener. Но прежде чем это сделать, хотел узнать - как делать грамотнее.