Search code examples
phpsymfonysymfony4symfony-security

Can I create something similar to isGranted in symfony?


So basically I want to create something like @IsGranted. I used @IsGranted on my application to access control to prevent a simple user from accessing an admin page for example.

On my entity, I have a boolean field called is_Active

  • if it's true (1) then the user can use his account
  • if it's false (0) then he gets redirected to an error page!

In this case, I am not going to test on the Rolesfield of the user but I am gonna test on the is_Active field that's why I can't use the @IsGranted.

I created an error twig page active.html.twig and I place it on templates folder, and I found myself FORCED to add those 2 lines on every controller function.

if ($this->getUser()->getIsActive()==false) {
     return $this->render('active.html.twig');}

Here is an example:

/**
 * @IsGranted("ROLE_ADMIN")
 * @Route("/", name="user_index", methods={"GET"})
 */
public function index(UserRepository $userRepository): Response
{
    if ($this->getUser()->getIsActive()==false) {
        return $this->render('active.html.twig');}
            
    return $this->render('user/index.html.twig', [
        'users' => $userRepository->findAll(),
    ]);
}

This is very heavy and bad to add this if statement on every function (I have +30 functions on the app)

Maybe I can create something similar to @IsGranted and use it on the annotation of each function instead?


Solution

  • You can keep using @IsGranted with a custom voter. https://symfony.com/doc/current/security/voters.html#creating-the-custom-voter

    Create new voter like in the documentation

    public const ACTIVE = 'active';
    
    protected function supports(string $attribute, $subject)
    {
        return $attribute === self::ACTIVE;
    }
    
    protected function voteOnAttribute(string $attribute, $subject, TokenInterface $token)
    {
        $user = $token->getUser();
    
        if ($user instanceof User && !$user->isActive()) {
            throw new InactiveUserException();
        }
    
        return true;
    }
    

    Then you can create a listener for InactiveUserException and show what ever you want to the client.

    In your controller you'll need to put @IsGranted("active") or @Security(expression="is_granted('active')") before the route method or controller