src/EventListener/RequestSignListener.php line 27

Open in your IDE?
  1. <?php
  2. namespace App\EventListener;
  3. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  4. use Symfony\Component\HttpFoundation\JsonResponse;
  5. use Symfony\Component\HttpFoundation\Request;
  6. use Symfony\Component\HttpKernel\Event\RequestEvent;
  7. use Symfony\Component\HttpKernel\KernelEvents;
  8. class RequestSignListener implements EventSubscriberInterface
  9. {
  10.     /**
  11.      * @var string
  12.      */
  13.     private string $clientSecret;
  14.     public function __construct(string $clientSecret)
  15.     {
  16.         $this->clientSecret $clientSecret;
  17.     }
  18.     /**
  19.      * Проверка подписи запроса
  20.      * @phpstan-ignore-next-line
  21.      */
  22.     public function onRequest(RequestEvent $event)
  23.     {
  24.         if (!$event->isMainRequest()) {
  25.             return;
  26.         }
  27.         $request $event->getRequest();
  28.         if ('/api/' === substr($request->getPathInfo(), 05)) {
  29.             if (!$this->isRequestFromVKSignedCorrectly($request)) {
  30.                 $event->setResponse($this->createAccessDeniedResponse('Access denied.'));
  31.             }
  32.         }
  33.     }
  34.     public static function getSubscribedEvents(): array
  35.     {
  36.         return [
  37.             KernelEvents::REQUEST => 'onRequest',
  38.         ];
  39.     }
  40.     private function isRequestFromVKSignedCorrectly(Request $request): bool
  41.     {
  42.         $queryParams = [];
  43.         parse_str(parse_url($request->getRequestUri(), PHP_URL_QUERY), $queryParams);
  44.         $signParams = [];
  45.         foreach ($queryParams as $name => $value) {
  46.             if (strpos($name'vk_') !== 0) {
  47.                 continue;
  48.             }
  49.             $signParams[$name] = $value;
  50.         }
  51.         if (empty($signParams) || !isset($queryParams['sign'])) {
  52.             return false;
  53.         }
  54.         ksort($signParams);
  55.         $signParamsQuery http_build_query($signParams);
  56.         $sign rtrim(strtr(base64_encode(hash_hmac(
  57.             'sha256',
  58.             $signParamsQuery,
  59.             $this->clientSecret,
  60.             true
  61.         )), '+/''-_'), '=');
  62.         return $sign === $queryParams['sign'];
  63.     }
  64.     private function createAccessDeniedResponse(string $message): JsonResponse
  65.     {
  66.         $response = new JsonResponse([
  67.             'errorMsg' => $message,
  68.             'success' => false,
  69.         ]);
  70.         $response->setStatusCode(403);
  71.         $response->headers->set('Content-type''application/json; charset=UTF-8');
  72.         return $response;
  73.     }
  74. }