Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to retrieve full role hierarchy in Symfony

Tags:

symfony

I'm using symfony2 role hierarchy, it works well, but in order to perform some changes, i have to retrieve the role_hierarchy set up in my security.yml.

role_hierarchy:
ROLE_USER: [ROLE_ACCESS_USER, ROLE_ACCESS_DATA, ROLE_ACCESS_PRODUCT]

Using getRoles() just return ROLE_USER, how can i know in my code that ROLE_USER is made with ROLE_ACCESS_USER, ROLE_ACCESS_DATA, ROLE_ACCESS_PRODUCT?

thanks for helping.

like image 889
linibou Avatar asked Jan 19 '12 14:01

linibou


3 Answers

You can get the hierarchy from the container:

$container->getParameter('security.role_hierarchy.roles')
like image 139
Kris Wallsmith Avatar answered Nov 20 '22 02:11

Kris Wallsmith


With auto wiring enabled, you can also directly inject the RoleHierarchy object filled with the global role hierarchy. Simply inject the RoleHierarchyInterface in your controller or service by using dependency injection:

use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;

public function __construct(RoleHierarchyInterface $roleHierarchy)
{
    $this->roleHierarchy = $roleHierarchy;
}

Note: This also allows you to call getReachableRoles() on the RoleHierarchy object, which could be useful in your case:

use Symfony\Component\Security\Core\Role\Role;

$this->roleHierarchy->getReachableRoles([new Role('ROLE_USER')]);

$this->roleHierarchy->getReachableRoleNames(['ROLE_USER']); // Symfony 5+

As of Symfony4 you have to add an alias for security.role_hierarchy in your config/services.yml by adding the following line:

services:
    # creating alias for RoleHierarchyInterface
    Symfony\Component\Security\Core\Role\RoleHierarchyInterface: '@security.role_hierarchy'
like image 24
Tim Wißmann Avatar answered Nov 20 '22 02:11

Tim Wißmann


Symfony 5 answer

namespace App\Controller;

...
use Symfony\Component\Security\Core\Role\RoleHierarchyInterface;
use Symfony\Component\Security\Core\Role\RoleHierarchy;

class UserController extends AbstractController
{
    private $roleHierarchy;

    /**
     * @Route("/users", name="users")
     */
    public function usersIndex(RoleHierarchyInterface $roleHierarchy)
    {
        $this->roleHierarchy = $roleHierarchy;

        // your user service or your Doctrine code here
        $users = ...

        foreach ($users as $user) {
            if ($this->isGranted($user, 'ROLE_SUPER_ADMIN')) {
                ...
            }
        }
        ...
    }

    private function isGranted(User $user, string $role): bool 
    {
        $reachableRoles = $this->roleHierarchy->getReachableRoleNames($user->getRoles());

        foreach ($reachableRoles as $reachableRole) {
            if ($reachableRole === $role) {
                return true;
            }
        }

        return false;
    }
}

Note: I put everything in the controller for the sake of simplicity here, but of course I'd recommend to move the Role Management code into your own dedicated role service.

like image 40
Erdal G. Avatar answered Nov 20 '22 00:11

Erdal G.