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.
@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.