我们正在使用Symfony2的角色功能来限制用户访问我们应用的某些部分。我们的每个用户实体都有许多具有开始日期和结束的订阅实体,用户可以购买年度订阅。
现在,有没有办法根据用户是否拥有“有效”订阅动态添加角色?在rails中,我只是让模型处理它是否具有必要的权限,但我知道通过设计symfony2实体不应该有权访问Doctrine。
我知道您可以从实体实例中访问实体的关联,但是这将通过 所有 用户的订阅对象,这对我来说似乎是不必要的麻烦。< / p>
答案 0 :(得分:27)
我认为你最好设置一个自定义选民和属性。
/**
* @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 }
答案 1 :(得分: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的情况一样,该角色将被查询覆盖。 您需要一个自定义提供程序来避免这种情况。