src/Security/DiscordAuthenticator.php line 44

Open in your IDE?
  1. <?php 
  2. namespace App\Security;
  3. use App\Entity\Groups;
  4. use App\Entity\User// your user entity
  5. use App\Entity\LoginLogs;
  6. use App\Service\Browser;
  7. use Doctrine\Persistence\ManagerRegistry;
  8. use Doctrine\ORM\EntityManagerInterface;
  9. use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
  10. use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator;
  11. use Symfony\Component\HttpFoundation\RedirectResponse;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\Routing\RouterInterface;
  15. use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
  16. use Symfony\Component\Security\Core\Exception\AuthenticationException;
  17. use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
  18. use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
  19. use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
  20. class DiscordAuthenticator extends OAuth2Authenticator
  21. {
  22.     private $clientRegistry;
  23.     private $entityManager;
  24.     private $router;
  25.     private $browser;
  26.     public function __construct(ClientRegistry $clientRegistryEntityManagerInterface $entityManagerRouterInterface $routerBrowser $browser)
  27.     {
  28.         $this->clientRegistry $clientRegistry;
  29.         $this->entityManager $entityManager;
  30.         $this->router $router;
  31.         $this->browser $browser;
  32.     }
  33.     public function supports(Request $request): ?bool
  34.     {
  35.         // continue ONLY if the current ROUTE matches the check ROUTE
  36.         return $request->attributes->get('_route') === 'connect_discord_check';
  37.     }
  38.     public function authenticate(Request $request): Passport
  39.     {
  40.         $client $this->clientRegistry->getClient('discord');
  41.         $accessToken $this->fetchAccessToken($client);
  42.         return new SelfValidatingPassport(
  43.             new UserBadge($accessToken->getToken(), function() use ($accessToken$client$request) {
  44.                 /** @var DiscordUser $discordUser */
  45.                 $discordUser $client->fetchUserFromToken($accessToken);
  46.                 $email $discordUser->getEmail();
  47.                 // 1) have they logged in with Discord before? Easy!
  48.                 $existingUser $this->entityManager->getRepository(User::class, 'default')->findOneBy(['discordId' => $discordUser->getId()]);
  49.                 if ($existingUser) {
  50.                     $existingUser->setUsername($discordUser->getUsername());
  51.                     $existingUser->setEmail($discordUser->getEmail());
  52.                     if ( !empty( $discordUser->getAvatarHash() ) ) {
  53.                         $existingUser->setAvatar($discordUser->getAvatarHash());
  54.                     }
  55.                     $this->entityManager->persist($existingUser);
  56.                     $this->entityManager->flush();
  57.                     $loginLogs = new LoginLogs();
  58.                     $loginLogs->setCreatedAt(new \DateTimeImmutable('NOW'));
  59.                     $loginLogs->setUser($existingUser);
  60.                     $loginLogs->setBrowser($this->browser->getBrowser() . ' (' $this->browser->getVersion() . ') / ' $this->browser->getPlatform() );
  61.                     $loginLogs->setAddressIp($request->getClientIp());
  62.                     $this->entityManager->persist($loginLogs);
  63.                     $this->entityManager->flush();
  64.                     return $existingUser;
  65.                 }
  66.                 // 2) do we have a matching user by email?
  67.                 $user $this->entityManager->getRepository(User::class, 'default')->findOneBy(['discordId' => $discordUser->getId()]);
  68.                 $group $this->entityManager->getRepository(Groups::class)->find(2);
  69.                 // 3) Maybe you just want to "register" them by creating
  70.                 // a User object
  71.                 $user = new User();
  72.                 $user->setDiscordId($discordUser->getId());
  73.                 $user->setGroupId($group);
  74.                 // $user->setSubgroups(array());
  75.                 $user->setEmail($discordUser->getEmail());
  76.                 if ( !empty( $discordUser->getAvatarHash() ) ) {
  77.                     $user->setAvatar($discordUser->getAvatarHash());
  78.                 }
  79.                 $user->setUsername($discordUser->getUsername());
  80.                 $user->setRoles(['ROLE_USER']);
  81.                 $user->setJoinDate(new \DateTimeImmutable('NOW'));
  82.                 $this->entityManager->persist($user);
  83.                 $this->entityManager->flush();
  84.                 $loginLogs = new LoginLogs();
  85.                 $loginLogs->setCreatedAt(new \DateTimeImmutable('NOW'));
  86.                 $loginLogs->setUser($user);
  87.                 $loginLogs->setBrowser($this->browser->getBrowser() . ' (' $this->browser->getVersion() . ') / ' $this->browser->getPlatform() );
  88.                 $loginLogs->setAddressIp($request->getClientIp());
  89.                 $this->entityManager->persist($loginLogs);
  90.                 $this->entityManager->flush();
  91.                 return $user;
  92.             })
  93.         );
  94.     }
  95.     public function onAuthenticationSuccess(Request $requestTokenInterface $tokenstring $firewallName): ?Response
  96.     {
  97.         // change "app_homepage" to some route in your app
  98.         $targetUrl $this->router->generate('app_home');
  99.         return new RedirectResponse($targetUrl);
  100.     
  101.         // or, on success, let the request continue to be handled by the controller
  102.         //return null;
  103.     }
  104.     public function onAuthenticationFailure(Request $requestAuthenticationException $exception): ?Response
  105.     {
  106.         $message strtr($exception->getMessageKey(), $exception->getMessageData());
  107.         return new Response($messageResponse::HTTP_FORBIDDEN);
  108.     }
  109. }