I'm migrating an app from Symfony 3.4 to Symfony 4.4. This app gives admin users the possibility to edit the role needed to access each route, so all the roles and routes are stored in the database.
To check if the user has access to a route, a voter is called on each request, and is configured in the services.yaml
file.
In Symfony 3.4, the voter was called on each request, without adding any more code. In the web profiler, i can see the list of voters, and the decision from the AccessDecisionManager ("Granted" or "Denied").
Screenshot of the Web Profiler for Symfony 3.4
In Symfony 4.4 however, the voters don't seem to be called at all. In the web profiler, my custom voter is still in the list (two times ??), but there is no decision from the AccessDecisionManager.
Screenshot of the Web Profiler for Symfony 4.4
If I check user access directly from the controller by adding this line $this->denyAccessUnlessGranted("", $request);
, the voters are called and work as expected.
If someone could explain to me why I have to call the denyAccessUnlessGranted()
method manually in Symfony 4.4 when it was not needed in Symfony 3.4 ? Was I using voters the wrong way in 3.4 ?
Thank you.
My custom voter class :
namespace App\Security;use Doctrine\ORM\EntityManager;use Symfony\Component\HttpFoundation\Request;use Symfony\Component\Security\Core\User\UserInterface;use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;use Symfony\Component\Security\Core\Authorization\Voter\VoterInterface;class DynamicAccessVoter implements VoterInterface{ // Routes everyone has access to const PUBLIC_ROUTES = ["login" ]; // Routes everyone who's connected has access to const PRIVATE_ROUTES = ["homepage","fos_js_routing","fos_js_routing_js" ]; // Routes everyone has access to only in dev mode const DEV_ROUTES = ["_wdt","_profiler","_profiler_home","_profiler_search","_profiler_search_bar","_profiler_phpinfo","_profiler_search_results","_profiler_open_file","_profiler_router","_profiler_exception","_profiler_exception_css","_twig_error_test" ]; private $env; /** * Constructor * * @param string $env - App environment (dev or prod) */ public function __construct(String $env = "") { $this->env = $env; } /** * Custom voter * * @param TokenInterface $token * @param Request $subject * @param array $env */ public function vote($token, $subject, $attributes) { // Verifie si $subject est une instance de Request if(!$subject instanceof Request) { return self::ACCESS_ABSTAIN; } $route = $subject->attributes->get("_route"); // Verifie si la route est une route publique (accessible par tout le monde) if(in_array($route, DynamicAccessVoter::PUBLIC_ROUTES)) { return self::ACCESS_GRANTED; } // Verifie si l'application est en développement et la route nécéssaire pour le debug if($this->env == "dev" && in_array($route, DynamicAccessVoter::DEV_ROUTES)) { return self::ACCESS_GRANTED; } // Verifie si $utilisateur est une instance de UserInterface if(!$token->getUser() instanceof UserInterface) { return self::ACCESS_ABSTAIN; } // Verifie si la route est une route accéssible par tout utilisateur connecté if(in_array($route, DynamicAccessVoter::PRIVATE_ROUTES)) { return self::ACCESS_GRANTED; } // Verifie si l'utilisateur connectéà le droit d'accéder à cette route if($token->getUser()->hasAccessTo($route)) { return self::ACCESS_GRANTED; } return self::ACCESS_DENIED; }}
My custom voter configured as a service in the services.yaml file :
app.dynamic_access_voter: class: App\Security\DynamicAccessVoter arguments: ["%kernel.environment%"] tags: - { name: security.voter }
My security.yaml file, if that can help :
security: # https://symfony.com/doc/current/security.html#where-do-users-come-from-user-providers encoders: App\Entity\Utilisateur: algorithm: bcrypt providers: main: entity: class: App\Entity\Utilisateur property: email firewalls: main: anonymous: true provider: main pattern: ^/ form_login: login_path: login check_path: login always_use_default_target_path: true default_target_path: homepage logout: path: /logout target: /login user_checker: App\Security\EnabledUserChecker access_control: - { path: ^/ }