Check if a role is granted for a specific user in

2020-02-11 07:20发布

问题:

I want to check if a role is granted for a specific user in Symfony2 (not the logged user). I know that I can check it for the logged user by:

$securityContext = $this->get('security.context');

if (false === $securityContext->isGranted('VIEW', $objectIdentity)) {
        //do anything
}

but if I'm the logged user and I wand to check other user if isGranted ??

回答1:

The "VIEW" is a permission, not a role.

The best way to check if a user has a right (be it a role or permission) would be to access the AccessDecisionManager. Something like:

$token = new UsernamePasswordToken($user, 'none', 'none', $user->getRoles());
$attributes = is_array($attributes) ? $attributes : array($attributes);
$this->get('security.access.decision_manager')->decide($token, $attributes, $object);

See original answer here: https://stackoverflow.com/a/22380765/971254 for details.



回答2:

You just need to create a custom security context that will take a user object and generate a UserSecurityIdentity out of it. Here are the steps:

Create a new service in YourApp/AppBundle/Resources/config.yml

yourapp.security_context:
    class: YourApp\AppBundle\Security\Core\SecurityContext
    arguments: [ @security.acl.provider ]

Create a custom Security Context Class like this:

namespace YourApp\AppBundle\Security\Core;

use Symfony\Component\Security\Acl\Model\MutableAclProviderInterface;
use Symfony\Component\Security\Acl\Domain\ObjectIdentity;
use Symfony\Component\Security\Acl\Domain\UserSecurityIdentity;
use Symfony\Component\Security\Acl\Permission\MaskBuilder;

use Symfony\Component\Security\Acl\Exception\AclNotFoundException;
use Symfony\Component\Security\Acl\Exception\NoAceFoundException;

use YourApp\AppBundle\Document\User;

/**
 * Allows ACL checking against a specific user object (regardless of whether that user is logged in or not)
 *
 */
class SecurityContext
{
    public function __construct(MutableAclProviderInterface $aclProvider)
    {
        $this->aclProvider = $aclProvider;
    }

    public function isGranted($mask, $object, User $user)
    {
        $objectIdentity = ObjectIdentity::fromDomainObject($object);
        $securityIdentity = UserSecurityIdentity::fromAccount($user);

        try {
            $acl = $this->aclProvider->findAcl($objectIdentity, array($securityIdentity));
        } catch (AclNotFoundException $e) {
            return false;
        }

        if (!is_int($mask)) {
            $builder = new MaskBuilder;
            $builder->add($mask);

            $mask = $builder->get();
        }

        try {
            return $acl->isGranted(array($mask), array($securityIdentity), false);
        } catch (NoAceFoundException $e) {
            return false;
        }
    }
}

Now you can inject that service where needed, or use it from a controller like this:

$someUser = $this->findSomeUserFromYourDatabase();

if ($this->get('yourapp.security_context')->isGranted('VIEW', $article, $someUser) {
   // ...
}


回答3:

Checking roles for another user can not be done via the SecurityContext as this will always hold the current user's session token. Your task can be achieved for example via the getRoles method, if the user you need to check implements the UserInterface.

$otherUser = $this->get('doctrine')->...   // fetch the user

if( $otherUser instanceof \Symfony\Component\Security\Core\User\UserInterface  )
{ 
     $roles = $otherUser->getRoles();

     // your role could be VIEW or ROLE_VIEW, check the $roles array above. 
     if ( in_array( 'VIEW' , $roles ) )
     {
      // do something else
     }
}

If your user entity implement the FosUserBundle UserInterFace, that has a dedicated method hasRole. In that case you could use a one-liner:

$otherUser = $this->get('doctrine')->...   // fetch the user

if( $otherUser instanceof \FOS\UserBundle\Model\UserInterface  )
{ 
     // your role could be VIEW or ROLE_VIEW, check the proper role names
     if ( $otherUser->hasRole( 'VIEW' ) )
     {
      // do something else
     }
}


回答4:

The solution pointed by Debreczeni András is the right one.

One can also improve the user class by adding that logic as a method.

So in our user class (the one which implements the UserInterface) we simply add this method:

/**
 * @param string $role
 * @return bool
 */
public function hasRole($role)
{
    if (in_array($role, $this->getRoles())) {
        return true;
    }
    return false;
}

then we are able to use:

$someUser->hasRole('SOME_ROLE');


标签: symfony acl