Home > Enterprise >  How to use dump() or dd() inside a Symfony Custom Voter?
How to use dump() or dd() inside a Symfony Custom Voter?

Time:04-04

I have followed several example from symfony, api-platform and several stackoverflow examples but to no avail. I don't know if I am doing something wrong or I don't understand the concept of the voter and roles. When I tried to access the endpoint, it throws Only user with permission can view dashboard.

In services.yaml

app.user_permission:
        class: App\Security\SecurityVoter
        arguments: ['@security.access.decision_manager']
        tags:
            - { name: security.voter}

I created a custom voter to use. Here I have done several changes, deleted several things to adopt the example I saw on StackOverflow Example

use App\Entity\WorkshopSession;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface;


class SecurityVoter extends Voter {
        
        private $decisionManager;
        const VIEW = 'view';
        const EDIT = 'edit';

        
        public function __construct (AccessDecisionManagerInterface $decisionManager) {
            $this->decisionManager = $decisionManager;
        }
        

        protected function supports($attribute, $subject): bool {
            // if the attribute isn't one we support, return false
            if (!in_array($attribute, [self::VIEW, self::EDIT])) {
                return false;
            }
            
          return true;
           
        }
        /**
         * @param string $attribute
         * @param TokenInterface $token
         * @return bool
         */
        protected function voteOnAttribute($attribute, $object, TokenInterface $token): bool {
            $user = $token->getUser();
            
            if (!$user instanceof UserInterface) {
                // the user must be logged in; if not, deny access
                return false;
            }

            
           // check ROLE_USER 
            if ($this->security->isGranted('ROLE_USER')) {
                return true;
            }
            switch ($attribute) {
                case self::VIEW:
                    if($this->decisionManager->decide($token, ['ROLE_USER'])) {
                        return true;
                    }
                break;
                case self::EDIT:
                    if($this->decisionManager->decide($token, ['ROLE_USER'])) {
                        return true;
                    }
                break;

            }
            
            throw new \LogicException('This code should not be reached!');
        }
        
     
}

In my Entity, I defined something like this.

#[ApiResource(
    attributes: ["security" => "is_granted('ROLE_USER')"],
    collectionOperations: [
        "get",
        "post" => [
            "security_post_denormalize" => "is_granted('ROLE_USER)",
            "security_message" => "Only user with permission can create a dashboard.",
        ],
    ],
    itemOperations: [
        "get" => [ "security" => "is_granted('VIEW') " , "security_message" => "Only user with permission can view dashboard."],
        "put" => [ "security" => "is_granted('EDIT')", "security_message" => "Only user with permission can edit dashboard."],
    ],
)]

I am currently on Symfony 5.4.7 and I have tried to use the example code. Nothing seems to be working. I have to use dd() and dump(), nothing was printed on the console or profiler. I have used loggerInterface (maybe I didn't do it correctly), and I didn't get to see anything output to var.

CodePudding user response:

You're closer than you think. You don't need use Symfony\Component\Security\Core\Authorization\AccessDecisionManagerInterface. You can make use of Security class as follows.

use App\Entity\WorkshopSession;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\Security\Core\Authorization\Voter\Voter;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;


class SecurityVoter extends Voter {
        
        private $security;
        const VIEW = 'view';
        const EDIT = 'edit';

        
        public function __construct ( Security $security) {
            $this->security = $security;
        }
        

        protected function supports($attribute, $subject): bool {
            // if the attribute isn't one we support, return false
            $supportsAttribute = in_array($attribute, ['VIEW', 'EDIT']);
            $supportsSubject = $subject instanceof WorkshopSession;
    
            return $supportsAttribute && $supportsSubject;
           
        }
        /**
         * @param string $attribute
         * @param WorkshopSession $workshopSession
         * @param TokenInterface $token
         * @return bool
         */
        protected function voteOnAttribute($attribute, $subject, TokenInterface $token): bool {
            $user = $token->getUser();
            
            if (!$user instanceof UserInterface) {
                // the user must be logged in; if not, deny access
                return false;
            }

         
           
            dd($user);

           // check ROLE_USER 
            if ($this->security->isGranted('ROLE_USER')) {
                return true;
            }
            switch ($attribute) {
                case self::VIEW:
                    if($this->security->isGranted('ROLE_USER')) {
                        return true;
                    }
                break;
                case self::EDIT:
                    if($this->security->isGranted('ROLE_USER')) {
                        return true;
                    }
                break;

            }
            
            throw new \LogicException('This code should not be reached!');
        }
        
     
}

Meanwhile, you don't need to configure service for this.

To inject the voter into the security layer, you must declare it as a service and tag it with security.voter. But if you're using the default services.yaml configuration, that's done automatically for you!

In your entity

#[ApiResource(
    attributes: ["security" => "is_granted('ROLE_USER')"],
    collectionOperations: [
        "get",
        "post" => [
            "security_post_denormalize" => "is_granted('ROLE_USER')",
            "security_message" => "Only user with permission can create a dashboard.",
        ],
    ],
    itemOperations: [
        "get" => [ "security" => "is_granted('VIEW', object) " ],
        "put" => [ "security" => "is_granted('EDIT')", "security_message" => "Only user with permission can edit dashboard."],
    ],
)]

You can also read this for reference - API Platform

NOTE: you can use dd() - e.g. dd($user);

  • Related