动态添加角色给用户

时间:2012-01-16 11:16:42

标签: symfony user-roles

我们正在使用Symfony2的角色功能来限制用户访问我们应用的某些部分。我们的每个用户实体都有许多具有开始日期和结束的订阅实体,用户可以购买年度订阅。

现在,有没有办法根据用户是否拥有“有效”订阅动态添加角色?在rails中,我只是让模型处理它是否具有必要的权限,但我知道通过设计symfony2实体不应该有权访问Doctrine。

我知道您可以从实体实例中访问实体的关联,但是这将通过 所有 用户的订阅对象,这对我来说似乎是不必要的麻烦。< / p>

2 个答案:

答案 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的情况一样,该角色将被查询覆盖。 您需要一个自定义提供程序来避免这种情况。