src/Controller/SecurityController.php line 25

Open in your IDE?
  1. <?php
  2. namespace App\Controller;
  3. use App\Entity\User;
  4. use App\Services\CurlHttpClient;
  5. use App\Services\SeoManager;
  6. use Exception;
  7. use LogicException;
  8. use stdClass;
  9. use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
  10. use Symfony\Component\EventDispatcher\EventDispatcher;
  11. use Symfony\Component\EventDispatcher\EventDispatcherInterface;
  12. use Symfony\Component\HttpFoundation\Request;
  13. use Symfony\Component\HttpFoundation\Response;
  14. use Symfony\Component\Security\Core\Authentication\Token\Storage\TokenStorageInterface;
  15. use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
  16. use Symfony\Component\Security\Http\Authentication\AuthenticationUtils;
  17. use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;
  18. const EXTERNAL_LOGIN_ERROR 'external_login_error';
  19. class SecurityController extends AbstractController
  20. {
  21.     public function login(Request $requestSeoManager $seoManagerAuthenticationUtils $authenticationUtils): Response
  22.     {
  23.         $seoManager
  24.             ->setTitleAndDescription('security.login.seo.title''security.login.seo.description')
  25.             ->useLogo();
  26.         // get the login error if there is one
  27.         $error $authenticationUtils->getLastAuthenticationError();
  28.         // last username entered by the user
  29.         $lastUsername $authenticationUtils->getLastUsername();
  30.         return $this->render('Security/login.html.twig', [
  31.             'last_username' => $lastUsername,
  32.             'error' => $error,
  33.             EXTERNAL_LOGIN_ERROR => $request->query->get(EXTERNAL_LOGIN_ERROR),
  34.         ]);
  35.     }
  36.     public function logout(): void
  37.     {
  38.         throw new LogicException('This method can be blank - it will be intercepted by the logout key on your firewall.');
  39.     }
  40.     /**
  41.      * OAuth2 login with Facebook or Google
  42.      * Redirect to home if it succeeds
  43.      * Redirect to registration page if ti succeeds but user doesn't exist
  44.      * Redirect to login in case of fail
  45.      *
  46.      * @param Request $request
  47.      * @param CurlHttpClient $httpClient
  48.      * @param EventDispatcherInterface $eventDispatcher
  49.      * @param TokenStorageInterface $tokenStorage
  50.      * @return Response
  51.      */
  52.     public function externalLogin(
  53.         Request                  $request,
  54.         CurlHttpClient           $httpClient,
  55.         EventDispatcherInterface $eventDispatcher,
  56.         TokenStorageInterface    $tokenStorage
  57.     ): Response
  58.     {
  59.         $googleToken $request->query->get('id_token');
  60.         $facebookAccessToken $request->query->get('access_token');
  61.         $data $googleToken ?
  62.             $this->getGoogleData($googleToken$httpClient) :
  63.             $this->getFacebookData($facebookAccessToken$httpClient);
  64.         if ($data !== null && isset($data->email)) {
  65.             /** @var User $user */
  66.             $user $this->getDoctrine()
  67.                 ->getRepository(User::class)
  68.                 ->findOneBy(['email' => $data->email]);
  69.             if ($user) {
  70.                 $token = new UsernamePasswordToken($user$user->getPassword(), "public"$user->getRoles());
  71.                 $tokenStorage->setToken($token);
  72.                 $event = new InteractiveLoginEvent($request$token);
  73.                 /** @var EventDispatcher $eventDispatcher */
  74.                 $eventDispatcher->dispatch($event"security.interactive_login");
  75.                 return $this->redirectToRoute('whiplay_home');
  76.             }
  77.             $registrationData = ['email' => $data->email'external' => 'true'];
  78.             $firstNameKey 'first_name';
  79.             if (property_exists($data$firstNameKey)) {
  80.                 $registrationData[$firstNameKey] = $data->first_name;
  81.             }
  82.             if (property_exists($data'given_name')) {
  83.                 $registrationData[$firstNameKey] = $data->given_name;
  84.             }
  85.             $lastNameKey 'last_name';
  86.             if (property_exists($data$lastNameKey)) {
  87.                 $registrationData[$lastNameKey] = $data->last_name;
  88.             }
  89.             if (property_exists($data'family_name')) {
  90.                 $registrationData[$lastNameKey] = $data->family_name;
  91.             }
  92.             if (property_exists($data'name')) {
  93.                 $registrationData['user_name'] = $data->name;
  94.             }
  95.             return $this->redirectToRoute('app_register'$registrationData);
  96.         }
  97.         return $this->redirectToRoute('app_login', [EXTERNAL_LOGIN_ERROR => true]);
  98.     }
  99.     /**
  100.      * Fetch Google API with OAuth2 token to get user data
  101.      * returns null if it failed
  102.      *
  103.      * @param $token
  104.      * @param $httpClient
  105.      * @return mixed|null
  106.      */
  107.     private function getGoogleData($token$httpClient): ?stdClass
  108.     {
  109.         $data null;
  110.         try {
  111.             $url 'https://oauth2.googleapis.com/tokeninfo?id_token=' $token;
  112.             $response $httpClient->get($url);
  113.             $response json_decode($response);
  114.             if ($response instanceof stdClass && $response->email) {
  115.                 $data $response;
  116.             }
  117.         } catch (Exception $exception) {
  118.             $data null;
  119.         }
  120.         return $data;
  121.     }
  122.     /**
  123.      * Fetch Facebook API with OAuth2 token to get user data
  124.      * returns null if it failed
  125.      *
  126.      * @param $token
  127.      * @param $httpClient
  128.      * @return stdClass|null
  129.      */
  130.     private function getFacebookData($token$httpClient): ?stdClass
  131.     {
  132.         $data null;
  133.         try {
  134.             $clientId $this->getParameter('facebook_client_id');
  135.             $clientSecret $this->getParameter('facebook_client_secret');
  136.             $url 'https://graph.facebook.com/oauth/access_token?client_id=' $clientId '&client_secret=' $clientSecret '&grant_type=client_credentials';
  137.             $response $httpClient->get($url);
  138.             $response json_decode($response);
  139.             $appToken $response->access_token;
  140.             $url 'https://graph.facebook.com/debug_token?input_token=' $appToken '&access_token=' $token;
  141.             $response $httpClient->get($url);
  142.             $response json_decode($response);
  143.             if (isset($response->data) && $response->data->is_valid) {
  144.                 $url 'https://graph.facebook.com/me?fields=email,birthday,first_name,last_name&access_token=' $token;
  145.                 $response $httpClient->get($url);
  146.                 $response json_decode($response);
  147.                 if (isset($response->email)) {
  148.                     $data = new stdClass();
  149.                     $data->email $response->email;
  150.                     $data->pseudo $response->name ?? '';
  151.                     $data->firstName $response->given_name ?? '';
  152.                     $data->familyName $response->family_name ?? '';
  153.                 }
  154.             }
  155.         } catch (Exception $exception) {
  156.             $data null;
  157.         }
  158.         return $data;
  159.     }
  160. }