15

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

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

我知道您可以从实体实例中访问实体的关联,但这会遍历所有用户的订阅对象,这对我来说似乎不必要的麻烦。

4

2 回答 2

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 }
于 2012-01-16T16:45:37.447 回答
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 的情况一样,该角色会被查询覆盖。您需要一个自定义提供程序来避免这种情况。

于 2012-01-16T13:38:19.123 回答