Search code examples
phpsymfonyhierarchyrolessymfony-3.4

Restrict access to Symfony 3.4 route/method to one specific role using annotations


I have a role hierarchy in security.yml that looks like this:

role_hierarchy:
    ROLE_SUPERVISOR:   ROLE_USER
    ROLE_MANAGER:      ROLE_SUPERVISOR
    ROLE_SUPPORT:      ROLE_MANAGER
    ROLE_ADMIN:        ROLE_SUPPORT

In my controller I have the following definitions:

/**
 * Collect user details.
 *
 * @Route(
 *      "/course/site/new/customerdetails",
 *      name = "course_site_new_customerdetails"
 * )
 * @IsGranted("IS_AUTHENTICATED_FULLY")
 * @param Request $request
 * @return Response
 */
public function customerDetailsAction(Request $request): Response
{
    // prevent a manager from entering
    if ($this->getUser()->hasRole('ROLE_MANAGER')) {
        return $this->redirectToRoute('supervisor_index');
    }

Using annotations, is there a way that I can prevent access to this method/route for Managers, but let Supervisors in?

I know the obvious change would be to redefine the hierarchy, however Supervisors are "below" Managers in the chain.


Solution

  • @IsGranted is limited to ROLES and privileges voted on by security voters (roles are voted on by a specific voter) since your manager role apparently includes the supervisor role (for whatever reason). Hierarchies in the sense of roles work the way, that it essentially a tree, where the user role is at the root and it branches out from that one. The rules for your roles essentially should be:

    ROLE_MANAGER: ROLE_USER
    ROLE_SUPERVISOR: ROLE_MANAGER
    

    which should be read as "every manager is a user", and "every supervisor is a manager". With that one, @IsGranted('ROLE_SUPERVISOR') should be sufficient.

    However, you can be more explicit by using the @Security syntax and demand that the user returns a specific role on User::getRoles():

    @Security("'ROLE_SUPERVISOR' in user.getRoles()")
    

    (maybe user.roles is enough ... but I'm not quite sure).

    don't forget the use clause:

    use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
    

    Also please note, that roles are cached until logout.