src/System/Listener/User/Authentication/AuthenticationListener.php line 115

Open in your IDE?
  1. <?php
  2. declare(strict_types=1);
  3. namespace App\System\Listener\User\Authentication;
  4. use ApiPlatform\Core\Bridge\Symfony\Validator\Exception\ValidationException;
  5. use App\Entities\User\Admin;
  6. use App\Entities\User\UserInterface;
  7. use App\Infrastructure\Interfaces\Logger\MessageDirectorInterface;
  8. use App\Infrastructure\Interfaces\Logger\NetworkLoggerInterface;
  9. use App\System\Infrastructure\Implementation\Connection\Live\Event\User\AccessTokenRefreshedEvent;
  10. use App\System\Infrastructure\Implementation\Logger\User\Authentication\MessageBuilder;
  11. use App\UseCase\User\Event\Authentication\SuccessEvent;
  12. use App\UseCase\User\Read\TwoFactor\CodeValidationDto;
  13. use App\UseCase\User\Read\TwoFactor\CodeValidationHandler;
  14. use App\UseCase\User\Write\Authentication\SuccessHandler;
  15. use App\UseCase\User\Write\TwoFactor\CreationDto;
  16. use App\UseCase\User\Write\TwoFactor\CreationHandler;
  17. use Symfony\Component\EventDispatcher\EventSubscriberInterface;
  18. use Symfony\Component\HttpFoundation\RequestStack;
  19. use Symfony\Component\Messenger\MessageBusInterface;
  20. use Symfony\Component\Security\Http\Event\LoginSuccessEvent;
  21. use Symfony\Component\Validator\ConstraintViolation;
  22. use Symfony\Component\Validator\ConstraintViolationList;
  23. class AuthenticationListener implements EventSubscriberInterface
  24. {
  25.     public function __construct(
  26.         private readonly CreationHandler $twoFactorCreationHandler,
  27.         private readonly CodeValidationHandler $codeValidationHandler,
  28.         private readonly SuccessHandler $successHandler,
  29.         private readonly MessageDirectorInterface $messageDirector,
  30.         private readonly RequestStack $requestStack,
  31.         private readonly NetworkLoggerInterface $networkLogger,
  32.         private readonly MessageBusInterface $bus,
  33.     ) {
  34.     }
  35.     public static function getSubscribedEvents(): array
  36.     {
  37.         return [
  38.             LoginSuccessEvent::class => [
  39.                 [
  40.                     'loginSuccess',
  41.                     0,
  42.                 ],
  43.                 [
  44.                     'tokenCreated',
  45.                     1,
  46.                 ],
  47.             ],
  48.             SuccessEvent::class => 'authenticationSuccess',
  49.         ];
  50.     }
  51.     /**
  52.      * @param LoginSuccessEvent $event
  53.      * @throws \App\UseCase\User\Write\TwoFactor\Exception\UserAlreadyHasTwoFactorAuthenticationException
  54.      */
  55.     public function loginSuccess(LoginSuccessEvent $event): void
  56.     {
  57.         $request $event->getRequest();
  58.         $routeName $request->attributes->get('_route');
  59.         if ($routeName !== 'api_login_check') {
  60.             return;
  61.         }
  62.         $user $event->getPassport()?->getUser();
  63.         if (!$user instanceof UserInterface) {
  64.             return;
  65.         }
  66.         if (!$user instanceof Admin) {
  67.             return;
  68.         }
  69.         if (!$user->hasTwoFactorKey()) {
  70.             $this->twoFactorCreationHandler->handle(new CreationDto($user));
  71.             $response $event->getResponse();
  72.             $response->setStatusCode(400);
  73.             $response->setContent(
  74.                 json_encode([
  75.                     'qrcode' => $this->twoFactorCreationHandler->getQrCodeWithSecretBase64(),
  76.                     'identifier' => $this->twoFactorCreationHandler->getUserIdentifier(),
  77.                 ])
  78.             );
  79.         } else {
  80.             $data json_decode($request->getContent(), true);
  81.             if (isset($data['twoFaCode'])) {
  82.                 $result $this->codeValidationHandler->handle(
  83.                     new CodeValidationDto($user$data['twoFaCode'])
  84.                 );
  85. return;
  86.                 if ($result->valid) {
  87.                     $this->successHandler->handle(
  88.                         new \App\UseCase\User\Write\Authentication\SuccessDto($user)
  89.                     );
  90.                     return;
  91.                 }
  92.             }
  93.             $list = new ConstraintViolationList();
  94.             $list->add(new ConstraintViolation('Неверный код'null, [], null'twoFaCode'null));
  95.             throw new ValidationException($list);
  96.         }
  97.     }
  98.     public function authenticationSuccess(SuccessEvent $event): void
  99.     {
  100.         $request $this->requestStack->getMainRequest();
  101.         if (!$request) {
  102.             return;
  103.         }
  104.         $builder = new MessageBuilder();
  105.         $builder
  106.             ->setCountry('')
  107.             ->setIp($request->getClientIp() ?? '')
  108.             ->setUserAgent($request->headers->get('user-agent'''));
  109.         $this->messageDirector->setMessageBuilder($builder);
  110.         $this->networkLogger->publish($this->messageDirector);
  111.     }
  112.     /**
  113.      * Доставляем событие обновления токена пользователя в сокетные соединения
  114.      */
  115.     public function tokenCreated(LoginSuccessEvent $event): void
  116.     {
  117.         if (!$event->getResponse()) {
  118.             return;
  119.         }
  120.         $user $event->getUser();
  121.         $response json_decode($event->getResponse()->getContent(), true);
  122.         if (!$response || !$user instanceof UserInterface) {
  123.             return;
  124.         }
  125.         $this->bus->dispatch(
  126.             new AccessTokenRefreshedEvent(
  127.                 $user->getUserIdentifier(),
  128.                 $response['token'],
  129.             )
  130.         );
  131.     }
  132. }