Maël Nison
Maël Nison

Reputation: 7353

Get security token for non-logged user with Symfony

How can I get a security token for any user, not only the one currently logged in ?

I would like to be able to call isGranted() on a user fetched from the database

Upvotes: 3

Views: 5412

Answers (3)

Kim
Kim

Reputation: 1888

I think the best way is to call AccessDecisionManager manually - like $securityContext->isGranted() does as well but for the currently logged in user. This is good too if you are using Symfony Voters to determine access.

$token = new UsernamePasswordToken($userObject, 'none', 'main', $userObject->getRoles());
$hasAccess = $this->get('security.access.decision_manager')->decide($token, array('voter'), $optionalObjectToCheckAccessTo);

Upvotes: 3

Thomas Kelley
Thomas Kelley

Reputation: 10292

isGranted() comes from the Security service, so it would be hard/unnecessary to use that to get Roles without adjusting the state of the session.

Don't get me wrong, it's definitely possible... This would work, for example:

public function strangeAction()
{
    // Get your User, however you normally get it
    $user = $userRepository->find($id);
    // Save the current token so you can put it back later
    $previousToken = $this->get("security.context")->getToken();
    // Create a new token
    $token = new UsernamePasswordToken($user, null, "main", $user->getRoles());
    // Update the security context with the new token
    $this->get("security.context")->setToken($token);
    // Now you have access to isGranted()
    if ($this->get("security.context")->isGranted("ROLE_SOMETHING"))
    { /* Do something here */ }
    // Don't forget to reset the token!
    $this->get("security.context")->setToken($previousToken);
}

...but that really makes no sense.

In reality, you don't need the token. A much better way of doing this would be to add an isGranted() method into your User entity:

// Namespace\YourBundle\Entity\User.php

class User
{
    ...
    public function isGranted($role)
    {
    return in_array($role, $this->getRoles());
    }
    ...
}

Now you can get those roles in your controllers:

public function notSoStrangeAction()
{
    // Get your User, however you normally get it
    $user = $userRepository->find($id);
    // Find out if that User has a Role associated to it
    if ($user->isGranted("ROLE_SOMETHING"))
    { /* Do something here */ }
}

Upvotes: 4

Hydde87
Hydde87

Reputation: 719

I had the same requirements a while ago. So I implemented it myself. Since you require the hierarchy information from the container it is not possible advised to extend the user entity with this functionality though.

// first check if the role is inside the user roles of the user
// if not then check for each user role if it is a master role of the check role
public function isGranted($user, $checkrole){
    $userroles = $user->getRoles();
    if (in_array($checkrole, $userroles)){return true;}
    foreach ($userroles as $userrole){
        if ($this->roleOwnsRole($userrole, $checkrole)){return true;}
    }
    return false;
 }

// recursively loop over the subroles of the master to check if any of them are
// the suggested slave role. If yes then the masterrole is a master and has 
// the same grants as the slave.
private function roleOwnsRole($masterRole, $slaveRole, $checkvalidityroles=true, $hierarchy=null)
{
    if ($hierarchy===null){$hierarchy = $this->container->getParameter('security.role_hierarchy.roles');}
    if ($masterRole === $slaveRole){ return false; }
    if($checkvalidityroles && (!array_key_exists($masterRole, $hierarchy) || !array_key_exists($slaveRole, $hierarchy))){ return false; }

    $masterroles = $hierarchy[$masterRole];
    if(in_array($slaveRole, $masterroles)){
        return true;
        }else{
            foreach($masterroles as $masterrolerec){
                if ($this->roleOwnsRole($masterrolerec, $slaveRole, false, $hierarchy)){return true;}
            }
            return false;
        }
}

Upvotes: 3

Related Questions