Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dynamically adding roles to a user

We are using Symfony2's roles feature to restrict users' access to certain parts of our app. Users can purchase yearly subscriptions and each of our User entities has many Subscription entities that have a start date and an end.

Now, is there a way to dynamically add a role to a user based on whether they have an 'active' subscription? In rails i would simply let the model handle whether it has the necessary rights but I know that by design symfony2 entities are not supposed to have access to Doctrine.

I know that you can access an entity's associations from within an entity instance but that would go through all the user's subscription objects and that seems unnecessaryly cumbersome to me.

like image 543
maiwald Avatar asked Jan 16 '12 11:01

maiwald


People also ask

What is a dynamic role?

Dynamic roles represent the system groups that are created for the roles assigned to team members in context teams and shared teams. The system groups created in an application context representing the organizations that have members in the context team.


2 Answers

I think you would do better setting up a custom voter and attribute.

/**
 * @Route("/whatever/")
 * @Template
 * @Secure("SUBSCRIPTION_X")
 */
public function viewAction()
{
    // etc...
}

The SUBSCRIPTION_X role (aka attribute) would need to be handled by a custom voter class.

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
    }
}

You would need to configure and tag your voter:

services:
    subscription_voter:
        class: SubscriptionVoter
        public: false
        arguments: [ @doctrine.orm.entity_manager ]
        tags:
            - { name: security.voter }
like image 54
Kris Wallsmith Avatar answered Sep 21 '22 14:09

Kris Wallsmith


Assuming that you have the right relation "subscriptions" in your User Entity.

You can maybe try something like :

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');
}

Changing role can be done with :

$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);

But after a page change, the refreshUser function of the provider is called and sometimes, as this is the case with EntityUserProvider, the role is overwrite by a query. You need a custom provider to avoid this.

like image 26
webda2l Avatar answered Sep 17 '22 14:09

webda2l