Динамическое добавление роли пользователю
Мы используем функцию ролей Symfony2, чтобы ограничить доступ пользователей к определенным частям нашего приложения. Пользователи могут приобретать годовые подписки, и у каждой из наших сущностей User
есть много сущностей Subscription
, у которых есть дата начала и окончания.
Теперь, есть ли способ динамически добавить роль пользователю, основываясь на том, есть ли у него "активная" подписка? В рельсах я бы просто позволил модели справиться с тем, обладает ли она необходимыми правами, но я знаю, что по замыслу сущности symfony2 не должны иметь доступа к Doctrine.
Я знаю, что вы можете получить доступ к ассоциациям сущностей из экземпляра сущности, но это будет проходить через все объекты пользовательской подписки, и это мне кажется излишне громоздким.
Ответы
Ответ 1
Думаю, вам лучше настроить пользовательский избиратель и атрибут.
/**
* @Route("/whatever/")
* @Template
* @Secure("SUBSCRIPTION_X")
*/
public function viewAction()
{
// etc...
}
Роль SUBSCRIPTION_X
(ака-атрибут) должна обрабатываться пользовательским классом избирателя.
class SubscriptionVoter implements VoterInterface
{
private $em;
public function __construct($em)
{
$this->em = $em;
}
public function supportsAttribute($attribute)
{
return 0 === strpos($attribute, 'SUBSCRIPTION_');
}
public function supportsClass($class)
{
return true;
}
public function vote(TokenInterface $token, $object, array $attributes)
{
// run your query and return either...
// * VoterInterface::ACCESS_GRANTED
// * VoterInterface::ACCESS_ABSTAIN
// * VoterInterface::ACCESS_DENIED
}
}
Вам нужно будет настроить и пометить своего избирателя:
services:
subscription_voter:
class: SubscriptionVoter
public: false
arguments: [ @doctrine.orm.entity_manager ]
tags:
- { name: security.voter }
Ответ 2
Предполагая, что у вас есть правильное отношение "подписки" в вашем пользовательском объекте.
Возможно, вы можете попробовать что-то вроде:
public function getRoles()
{
$todayDate = new DateTime();
$activesSubscriptions = $this->subscriptions->filter(function($entity) use ($todayDate) {
return (($todayDate >= $entity->dateBegin()) && ($todayDate < $entity->dateEnd()));
});
if (!isEmpty($activesSubscriptions)) {
return array('ROLE_OK');
}
return array('ROLE_KO');
}
Изменение роли может быть выполнено с помощью
$sc = $this->get('security.context')
$user = $sc->getToken()->getUser();
$user->setRole('ROLE_NEW');
// Assuming that "main" is your firewall name :
$token = new \Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken($user, null, 'main', $user->getRoles());
$sc->setToken($token);
Но после изменения страницы вызывается функция refreshUser провайдера и иногда, так как это имеет место с EntityUserProvider, роль перезаписывается запросом.
Чтобы избежать этого, вам нужен пользовательский поставщик.