Brian
Brian

Reputation: 7135

How to a dynamically add roles to a user?

When a user logs in, whether it be for the first time or via a cookie that's present, I want to assign them one or more additional user roles based on the result of some queries I run.

I think I need to create an Event Listener that gets the security component and entity manager injected, so I can run my queries and add roles to the current user.

I'm not quite sure if this is possible with events though, since the event would need to be fired within the Firewall context before the authorization is done, but after authentication.

I did see this existing question, but I can't get it to work (the roles are not actually recognized after the event is run).

Is it possible to do this with an event listener?

I think my alternative would be to use a postload lifecycle callback on the User entity and run some queries there, but that doesn't seem right.

Upvotes: 3

Views: 3779

Answers (1)

sketchthat
sketchthat

Reputation: 2688

You could create an event listener on the kernel. It will run everytime a page is loaded.

It will check if their is a logged in user and then you can do some custom logic to see if you need to update their role, if you do then update it log them in with the new settings and then they'll continue in the system with their new role.

I haven't tested this code, so it might have some bugs.

services.yml

bundle.eventlistener.roles:
    class: Sample\MyBundle\EventListener\Roles
    arguments: [@service_container, @security.context]
    tags:
        - { name: kernel.event_listener, event: kernel.controller, method: onKernelController }

Listener\Roles.php

namespace Sample\MyBundle\EventListener;

use Symfony\Component\DependencyInjection\ContainerInterface as Container;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;

use Sample\MyBundle\Entity\Users; //Your USER entity

class Roles {
    private $container;
    private $context;

    public function __construct(Container $container, SecurityContext $context) {
        $this->container = $container;
        $this->context = $context;
    }

    public function onKernelController(FilterControllerEvent $event) {
        if($this->context->getToken()->getUser() instanceof Users) {

            //Custom logic to see if you need to update the role or not.

            $user = $this->context->getToken()->getUser();

            //Update your roles
            $user->setRole('ROLE_WHATEVER');

            $em = $this->container->get('doctrine')->getManager();
            $em->persist($user);
            $em->flush();

            //Create new user token
            //main == firewall setting
            $token = new UsernamePasswordToken($user, $user->getPassword(), 'main', $user->getRoles());

            $this->context->setToken($token);
        }
    }
}

Upvotes: 7

Related Questions