<?php
namespace App\Controller;
use App\Entity\ActiviteUser;
use App\Entity\User;
use App\Security\AppAuthenticator;
use GuzzleHttp\Client;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\Annotation\Route;
use League\OAuth2\Client\Provider\Google;
use Doctrine\ORM\EntityManagerInterface;
use Lexik\Bundle\JWTAuthenticationBundle\Services\JWTTokenManagerInterface;
use Symfony\Component\HttpFoundation\JsonResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Security\Http\Authentication\UserAuthenticatorInterface;
class GoogleController extends AbstractController
{
private Google $login_provider;
private Google $register_provider;
public function __construct()
{
$this->login_provider = new Google([
'clientId' => $_ENV['GGL_ID'],
'clientSecret' => $_ENV['GGL_SECRET'],
'redirectUri' => $_ENV['GGL_CALLBACK'],
'graphApiVersion' => 'v18.0',
]);
$this->register_provider = new Google([
'clientId' => $_ENV['GGL_ID'],
'clientSecret' => $_ENV['GGL_SECRET'],
'redirectUri' => $_ENV['GGL_CALLBACK_REGISTER'],
'graphApiVersion' => 'v18.0',
]);
}
/**
* @Route("/ggl-login", name="ggl_login")
*/
public function gglLogin(): Response
{
$helper_url = $this->login_provider->getAuthorizationUrl();
return $this->redirect($helper_url);
}
/**
* @Route("/ggl-save/register", name="ggl_save")
*/
public function gglRegister(): Response
{
$helper_url = $this->register_provider->getAuthorizationUrl();
return $this->redirect($helper_url);
}
/**
* @Route("/ggl-callback", name="ggl_callback")
* @throws IdentityProviderException
*/
public function gglCallBack(
EntityManagerInterface $manager,
UserAuthenticatorInterface $userAuthenticator,
AppAuthenticator $authenticator,
Request $request,
JWTTokenManagerInterface $jwtManager
): Response {
$token = $this->login_provider->getAccessToken('authorization_code', [
'code' => $_GET['code']
]);
try {
$user = $this->login_provider->getResourceOwner($token)->toArray();
$email = $user['email'];
$user_exist = $manager->getRepository(User::class)->findOneBy(['email' => $email]);
if ($user_exist) {
if (!empty($user['picture'])) {
$urlPhoto = $this->downloadAndSaveAvatar($user['picture']);
$user_exist->setPhoto($urlPhoto);
if ($user_exist->isFreelance()) {
$user_exist->getUniqueProfile()->setPhoto($urlPhoto);
}
}
return $userAuthenticator->authenticateUser($user_exist, $authenticator, $request);
} else {
$this->addFlash('error-google', "Votre compte google n'est pas associé à cette application.\n Veuillez vous inscrire!");
return $this->redirectToRoute('login');
}
} catch (\Throwable $th) {
$this->addFlash('error-google', "Une erreur est survenue lors de la connexion Google. Veuillez réessayer.");
return $this->redirectToRoute('login');
}
}
// Route pour afficher la page de redirection
/**
* @Route("/redirect-to-exp", name="redirect_to_exp")
*/
public function redirectToExp(Request $request): Response
{
$clientId = $request->query->get('client_id');
// Désactivé: aucune tentative d'ouverture d'application mobile
return new Response(
'<html>
<head>
<meta charset="UTF-8">
<title>Redirection</title>
</head>
<body>
<p>Aucune redirection vers une application mobile. Vous pouvez continuer sur le site.</p>
</body>
</html>'
);
}
/**
* @Route("/ggl-callback-register", name="ggl_callback_register")
* @throws IdentityProviderException
*/
public function gglCallBackRegister(
EntityManagerInterface $manager,
UserAuthenticatorInterface $userAuthenticator,
AppAuthenticator $authenticator,
Request $request,
JWTTokenManagerInterface $jwtManager
): Response {
$token = $this->register_provider->getAccessToken('authorization_code', [
'code' => $_GET['code']
]);
try {
$googleUser = $this->register_provider->getResourceOwner($token)->toArray();
$email = $googleUser['email'];
$user_exist = $manager->getRepository(User::class)->findOneBy(['email' => $email]);
if ($user_exist) {
if (!empty($googleUser['picture'])) {
$urlPhoto = $this->downloadAndSaveAvatar($googleUser['picture']);
$user_exist->setPhoto($urlPhoto);
if ($user_exist->isFreelance()) {
$user_exist->getUniqueProfile()->setPhoto($urlPhoto);
}
}
return $userAuthenticator->authenticateUser($user_exist, $authenticator, $request);
} else {
$user = new User();
$user->setCreatedAt(new \DateTime());
$user->setRoles(['ROLE_FREELANCE']);
$user->setType('freelance');
$user->setPhone('');
$user->setEmail($googleUser['email']);
$user->setPassword('__GOOGLE__AUTH__');
$user->setLastname($googleUser['family_name'] ?? " ");
$user->setFirstname($googleUser['given_name'] ?? " ");
$user->setGoogleSubId($googleUser['sub']);
$user->setIsVerified(true);
if (!empty($googleUser['picture'])) {
$urlPhoto = $this->downloadAndSaveAvatar($googleUser['picture']);
$user->setPhoto($urlPhoto);
$user->getUniqueProfile()->setPhoto($urlPhoto);
}
$manager->persist($user);
$manager->flush();
$user->setPassword($user->getId() . '__GOOGLE__AUTH__');
$manager->persist($user);
$manager->flush();
return $userAuthenticator->authenticateUser($user, $authenticator, $request);
}
} catch (\Throwable $th) {
$this->addFlash('error-google', "Une erreur est survenue lors de l'inscription Google. Veuillez réessayer.");
return $this->redirectToRoute('login');
}
}
/**
* @Route("/api/mobile/google", name="mobile_google_login", methods={"POST"})
*/
public function googleLogin(Request $request, EntityManagerInterface $manager, JWTTokenManagerInterface $jwtManager): JsonResponse
{
// Récupérer le token envoyé depuis l'application mobile
$data = json_decode($request->getContent(), true);
$idToken = $data['id_token'] ?? null;
if (!$idToken) {
return new JsonResponse(['error' => 'Token manquant'], 400);
}
// Vérifier le token via Google
// $client = new Google_Client(['client_id' => $_ENV['GGL_ID']]); // ID client de ton app
// $payload = $client->verifyIdToken($idToken);
$client = new \GuzzleHttp\Client();
$response = $client->get('https://oauth2.googleapis.com/tokeninfo', [
'query' => ['id_token' => $idToken],
]);
if ($response->getStatusCode() !== 200) {
throw new \Exception('Token invalide');
}
$payload = json_decode($response->getBody(), true);
// Vérifie que l'audience (aud) correspond à ton client_id
if ($payload['aud'] !== $_ENV['GGL_ID']) {
throw new \Exception('Token émis pour un autre client_id');
}
if (!$payload) {
return new JsonResponse(['error' => 'Token invalide'], 401);
}
$email = $payload['email'];
$sub = $payload['sub']; // Le sub (ID unique) est important pour identifier l'utilisateur
// Chercher l'utilisateur dans la base
$user = $manager->getRepository(User::class)->findOneBy(['email' => $email]);
if (!$user) {
// Si l'utilisateur n'existe pas, le créer
$user = new User();
$user->setEmail($email);
$user->setFirstname($payload['given_name'] ?? ""); // Optionnel
$user->setLastname($payload['family_name'] ?? ""); // Optionnel
$user->setGoogleSubId($sub); // ID unique de Google pour la liaison
$user->setPassword('__GOOGLE__AUTH__'); // Utilise un mot de passe fictif pour Google
$manager->persist($user);
$manager->flush();
}
// Générer le JWT avec LexikJWT
$token = $jwtManager->create($user); // Création du JWT pour l'utilisateur
return new JsonResponse(['token' => $token]);
}
private function downloadAndSaveAvatar(string $imageUrl): ?string
{
$client = new Client();
$publicDir = $this->getParameter('avatar_directory') . '/';
try {
// Faire une requête GET pour télécharger l'image
$response = $client->get($imageUrl);
$contentType = $response->getHeader('Content-Type')[0];
// Vérifier si c'est une image
if (strpos($contentType, 'image/') !== 0) {
throw new \Exception("Ce n'est pas une image valide.");
}
// Déterminer l'extension de l'image
$extension = explode('/', $contentType)[1]; // par exemple "jpeg" ou "png"
// Générer un nom unique pour l'image
$uniqueFileName = 'avatar-' . uniqid() . '.' . $extension;
// Chemin complet pour enregistrer l'image
$filePath = $publicDir . $uniqueFileName;
// Enregistrer l'image localement
file_put_contents($filePath, $response->getBody());
return $uniqueFileName; // Retourner le nom du fichier enregistré
} catch (\Exception $e) {
// Gérer l'erreur
return null;
}
}
}