26

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.

2
  • What do you need it for? Jan 19, 2012 at 14:58
  • my "user" (ROLE_USER) have a default set of roles, i want to permit an admin to give him only specifics roles, e.g only ROLE_ACCESS_DATA. I want to do that via an interface showing all existing roles.
    – linibou
    Jan 19, 2012 at 15:31

5 Answers 5

44

You can get the hierarchy from the container:

$container->getParameter('security.role_hierarchy.roles')
0
22

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'
3
8

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.

3
  • $roles = $roleHierarchy->getReachableRoleNames($user->getRoles()); is not used in usersIndex() method - is it forgotten statement?
    – long
    Nov 25, 2020 at 20:25
  • @long thanks no idea why that ended up here. Fixed :)
    – Erdal G.
    Nov 26, 2020 at 15:32
  • How can you overwrite the RoleHierarchy Interface with extended logic without mentioning it in the controller?
    – Jonathan
    Sep 29, 2021 at 12:05
0

For a correct representation of your roles, you need recursion. Roles can extend other roles.

Here is an example: https://stackoverflow.com/a/36900807/3635680

1
  • Please quote the relevant text in your answer. It's not recommended to post link-only answers (even if the link leads to Stack Overflow).
    – A.L
    Sep 13, 2016 at 20:33
0

security.role_hierarchy.roles is all security roles defined in security.yml

If you want to include Sonata Admin roles, you could check code in SonataUserBundle\Form\Type\SecurityRolesType

foreach ($this->pool->getAdminServiceIds() as $id) {
            try {
                $admin = $this->pool->getInstance($id);
            } catch (\Exception $e) {
                continue;
            }

            $securityHandler = $admin->getSecurityHandler();

            foreach ($securityHandler->buildSecurityInformation($admin) as $role => $acls) {
                $roles[$role] = $role;
            }
        }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.