LexikJWTAuthenticationBundle icon indicating copy to clipboard operation
LexikJWTAuthenticationBundle copied to clipboard

Override the Token Roles

Open mnavarrocarter opened this issue 7 years ago • 1 comments

I'm building an application that requires a very dynamic authorization system and it will be very useful to be able to override the JWTUserToken roles. I know that a setRoles() method in the JWTUserToken class will be kinda unconventional, since it's exposing to the whole application the chance of modifiying the token roles.

I'm currently using relfection to modify the token roles, but I think it will be good to have a cleaner implementation.

So I was thinking if maybe would it be possible to implement a new event with a method to be executed just before the token creation so we can hook up into the roles definition. Something along these lines:

#JWTTokenAuthenticator:line225

$rolesEvent = new JWTTokenRolesDefinedEvent($user, $preAuthToken->getPayload());

$this->dispatcher->dispatch(Events::JWT_ROLES_DEFINED, $rolesEvent);

$authToken = new JWTUserToken($rolesEvent->getRoles(), $user, $preAuthToken->getCredentials(), $providerKey);

And of course, the RolesDefinedEvent class:

<?php

namespace Lexik\Bundle\JWTAuthenticationBundle\Event;

use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\Security\Core\User\UserInterface;

/**
 * JWTRolesDefinedEvent.
 */
class JWTRolesDefinedEvent extends Event
{
    /**
     * @var UserInterface
     */
    protected $user;

    /**
     * @var array
     */
    protected $payload;

    /**
     * @var array
     */
    protected $roles;

    /**
     * JWTRolesDefinedEvent constructor.
     * @param UserInterface $user
     * @param array $payload
     */
    public function __construct(UserInterface $user, array $payload)
    {
        $this->payload = $payload;
        $this->user   = $user;
        $this->roles = $user->getRoles();
    }

    /**
     * @return array
     */
    public function getPayload()
    {
        return $this->payload;
    }

    /**
     * @return UserInterface
     */
    public function getUser()
    {
        return $this->user;
    }
    
    /**
     * @return array
     */
    public function getRoles()
    {
        return $this->roles;
    }

    /**
     * @param array $roles
     * @return JWTRolesDefinedEvent
     */
    public function setRoles($roles)
    {
        $this->roles = $roles;
        return $this;
    }
}

If the event doesn't have a listener, the constructor will pass by default the roles of the authenticated user. Everything will keep working the same, but it gives the benefit of add some custom logic for the roles definition to those who desire so.

Just tell me what you think and I can send a PR with this.

PS: Sorry for my poor English.

mnavarrocarter avatar Jan 09 '18 14:01 mnavarrocarter

Or maybe, what would be event better, is allow the users to define their own token, and not just the roles. Same principle: constructor does the default, but it can be overriden. The event itself will can hold the login for the token creation.

mnavarrocarter avatar Jan 09 '18 14:01 mnavarrocarter