src/CoreBundle/Component/Router/Security/RouteCsrfProtector.php line 54

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\CoreBundle\Component\Router\Security;
  4. use App\CoreBundle\Component\Router\Security\Annotation\CsrfProtection;
  5. use Doctrine\Common\Annotations\Reader;
  6. use ReflectionMethod;
  7. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  8. use Symfony\Component\HttpKernel\Event\ControllerEvent;
  9. use Symfony\Component\HttpKernel\KernelEvents;
  10. use Symfony\Component\Security\Csrf\CsrfToken;
  11. use Symfony\Component\Security\Csrf\CsrfTokenManagerInterface;
  12. class RouteCsrfProtector implements EventSubscriberInterface
  13. {
  14.     public const CSRF_TOKEN_REQUEST_PARAMETER 'routeCsrfToken';
  15.     public const CSRF_TOKEN_ID_PREFIX 'route_';
  16.     /**
  17.      * @var \Doctrine\Common\Annotations\Reader
  18.      */
  19.     protected $annotationReader;
  20.     /**
  21.      * @var \Symfony\Component\Security\Csrf\CsrfTokenManagerInterface
  22.      */
  23.     protected $tokenManager;
  24.     /**
  25.      * @param \Doctrine\Common\Annotations\Reader $annotationReader
  26.      * @param \Symfony\Component\Security\Csrf\CsrfTokenManagerInterface $tokenManager
  27.      */
  28.     public function __construct(Reader $annotationReaderCsrfTokenManagerInterface $tokenManager)
  29.     {
  30.         $this->annotationReader $annotationReader;
  31.         $this->tokenManager $tokenManager;
  32.     }
  33.     /**
  34.      * @return string[]
  35.      */
  36.     public static function getSubscribedEvents()
  37.     {
  38.         return [
  39.             KernelEvents::CONTROLLER => 'onKernelController',
  40.         ];
  41.     }
  42.     /**
  43.      * @param \Symfony\Component\HttpKernel\Event\ControllerEvent $event
  44.      */
  45.     public function onKernelController(ControllerEvent $event)
  46.     {
  47.         if ($this->isProtected($event)) {
  48.             $request $event->getRequest();
  49.             $csrfToken $request->get(self::CSRF_TOKEN_REQUEST_PARAMETER);
  50.             $routeName $request->get('_route');
  51.             if ($csrfToken === null || !$this->isCsrfTokenValid($routeName$csrfToken)) {
  52.                 throw new \Symfony\Component\HttpKernel\Exception\BadRequestHttpException('Csrf token is invalid');
  53.             }
  54.         }
  55.     }
  56.     /**
  57.      * @param string $routeName
  58.      * @return string
  59.      */
  60.     public function getCsrfTokenId($routeName)
  61.     {
  62.         return static::CSRF_TOKEN_ID_PREFIX $routeName;
  63.     }
  64.     /**
  65.      * @param string $routeName
  66.      * @return string
  67.      */
  68.     public function getCsrfTokenByRoute($routeName)
  69.     {
  70.         return $this->tokenManager->getToken($this->getCsrfTokenId($routeName))->getValue();
  71.     }
  72.     /**
  73.      * @param string $routeName
  74.      * @param string $csrfToken
  75.      * @return bool
  76.      */
  77.     protected function isCsrfTokenValid($routeName$csrfToken)
  78.     {
  79.         $token = new CsrfToken($this->getCsrfTokenId($routeName), $csrfToken);
  80.         return $this->tokenManager->isTokenValid($token);
  81.     }
  82.     /**
  83.      * @param \Symfony\Component\HttpKernel\Event\ControllerEvent $event
  84.      * @return bool
  85.      */
  86.     protected function isProtected(ControllerEvent $event)
  87.     {
  88.         if (!$event->isMasterRequest()) {
  89.             return false;
  90.         }
  91.         list($controller$action) = $event->getController();
  92.         $method = new ReflectionMethod($controller$action);
  93.         $annotation $this->annotationReader->getMethodAnnotation($methodCsrfProtection::class);
  94.         return $annotation !== null;
  95.     }
  96. }