Google OAuth-Integration für Symfony

Ich zeige dir in diesem Artikel eine vollständige Implementierung für die Google OAuth-Integration (SSO – Single Sign On) in deinem Symfony Projekt. Ich verwende die LTS Version 6.4. Dies ermöglicht Benutzern, sich mit ihrem Google-Konto bei dir zu registrieren und anzumelden.

Übersicht

Wir werden die Google OAuth-Integration mit dem KnpUOAuth2ClientBundle implementieren, das eine gute Integration mit Symfony Security bietet. Die Lösung wird folgende Komponenten umfassen:

  • Installation und Konfiguration der benötigten Pakete
  • Erstellung eines Google OAuth-Clients
  • Anpassung des Benutzermodells
  • Implementierung der Authentication-Handler
  • Frontend-Integration (Login-Button)

Was du schon haben solltest:

  • Grundlegende Symfony/PHP Erfahrung
  • Ein Symfony Projekt am besten ab Version 6.4
  • Einen fertigen Login und Registrierungsprozess (Symfony User)
  • Einen Google Account

Vorbereitende Aufgaben bei Google

Google OAuth Einrichtungsanleitung

Google Cloud Console Projekt erstellen

  1. Besuche die [Google Cloud Console] (https://console.cloud.google.com/)
  2. Erstelle ein neues Projekt oder wähle ein bestehendes Projekt aus
  3. Navigiere zum „OAuth consent screen“ (OAuth-Zustimmungsbildschirm) im Menü „APIs & Services“
  4. Wähle den Benutzertyp (extern oder intern) und gib die erforderlichen Informationen ein:
    – App-Name
    – Benutzer-Support-E-Mail
    – Entwickler-Kontakt-Informationen
  5. Speichere die Einstellungen

OAuth-Anmeldedaten erstellen

  1. Navigiere zu „Credentials“ (Anmeldedaten) im Menü „APIs & Services“
  2. Klicke auf „Create Credentials“ (Anmeldedaten erstellen) und wähle „OAuth client ID“ (OAuth-Client-ID)
  3. Wähle als Anwendungstyp „Web application“ (Webanwendung)
  4. Gib einen Namen für den Client ein
  5. Füge autorisierte Weiterleitungs-URIs hinzu:
    – Für die Entwicklungsumgebung: `http://localhost:8000/connect/google/check`
    – Für die Produktionsumgebung: `https://deine-domain.de/connect/google/check`
  6. Klicke auf „Create“ (Erstellen)
  7. Notiere dir die „Client ID“ und das „Client Secret“

Umgebungsvariablen konfigurieren

Füge die Client ID und das Client Secret zu deiner `.env.local` Datei hinzu:

GOOGLE_CLIENT_ID=deine-client-id
GOOGLE_CLIENT_SECRET=dein-client-secret

Google OAuth API aktivieren

  1. Navigiere zu „Library“ (Bibliothek) im Menü „APIs & Services“
  2. Suche nach „Google People API
  3. Aktiviere diese API für dein Projekt

Google OAuth-Integration in Symfony

Installation der benötigten Pakete

# Installation des KnpUOAuth2ClientBundle
composer require knpuniversity/oauth2-client-bundle

# Installation des Google OAuth2 Providers
composer require league/oauth2-google

# Falls noch nicht vorhanden, stelle sicher, dass die Symfony Security-Komponenten installiert sind
composer require symfony/security-bundle

Als Nächstes müssen wir die Konfiguration für das OAuth2-Bundle einrichten

# config/packages/knpu_oauth2_client.yaml
knpu_oauth2_client:
    clients:
        google:
            type: google
            client_id: '%env(GOOGLE_CLIENT_ID)%'
            client_secret: '%env(GOOGLE_CLIENT_SECRET)%'
            redirect_route: connect_google_check
            redirect_params: {}

Das Benutzermodell

Wir konfigurieren nun unser Benutzermodell, damit es die von Google bereitgestellten Nutzerdaten – wie Name, E-Mail-Adresse und Profilbild – aufnehmen und verwalten kann. Das heißt wir müssen unsere User Entity anpassen. Öffne dazu die src/Entity/User.php und führe folgende Änderungen durch:

 // Hier muss nullable: true hinzugefügt werden
#[ORM\Column(nullable: true)]
    private ?string $password = null;

// Folgende Felder müssen hinzugefügt werden
#[ORM\Column(length: 255, nullable: true)]
    private ?string $googleId = null;

#[ORM\Column(length: 255, nullable: true)]
    private ?string $locale = null;

#[ORM\Column(length: 255, nullable: true)]
    private ?string $avatarUrl = null;
    
#[ORM\Column(length: 255, nullable: true)]
    private ?string $registrationSource = null;

// Folgende Getter und Setter hinzufügen
public function getGoogleId(): ?string
    {
        return $this->googleId;
    }

public function setGoogleId(?string $googleId): static
    {
        $this->googleId = $googleId;
        return $this;
    }

public function getAvatarUrl(): ?string
    {
        return $this->avatarUrl;
    }

public function setAvatarUrl(?string $avatarUrl): static
    {
        $this->avatarUrl = $avatarUrl;
        return $this;
    }

public function getLocale(): ?string
    {
        return $this->locale;
    }

public function setLocale(?string $locale): static
    {
        $this->locale = $locale;
        return $this;
    }

public function getRegistrationSource(): ?string
    {
        return $this->registrationSource;
    }

public function setRegistrationSource(?string $registrationSource): static
    {
        $this->registrationSource = $registrationSource;
        return $this;
    }
    
public function isGoogleUser(): bool
    {
        return $this->googleId !== null;
    }

Migration der neuen Felder in der User Entity

# Migration erstellen
php bin/console make:migration

# Migration ausführen
php bin/console doctrine:migrations:migrate

Google Authenticator für Google OAuth

Folgende PHP Datei erstellen wir unter src/Security/GoogleAuthenticator.php

<?php

namespace App\Security;

use App\Entity\User;
use App\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator;
use League\OAuth2\Client\Provider\GoogleUser;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;

class GoogleAuthenticator extends OAuth2Authenticator implements AuthenticationEntryPointInterface
{
    private ClientRegistry $clientRegistry;
    private EntityManagerInterface $entityManager;
    private RouterInterface $router;
    private UserRepository $userRepository;

    public function __construct(
        ClientRegistry $clientRegistry,
        EntityManagerInterface $entityManager,
        RouterInterface $router,
        UserRepository $userRepository
    ) {
        $this->clientRegistry = $clientRegistry;
        $this->entityManager = $entityManager;
        $this->router = $router;
        $this->userRepository = $userRepository;
    }

    public function supports(Request $request): ?bool
    {
        // Prüfen, ob der aktuelle Request der Google-Callback ist
        return $request->attributes->get('_route') === 'connect_google_check';
    }

    public function authenticate(Request $request): Passport
    {
        $client = $this->clientRegistry->getClient('google');
        $accessToken = $this->fetchAccessToken($client);

        return new SelfValidatingPassport(
            new UserBadge($accessToken->getToken(), function() use ($accessToken, $client) {
                /** @var GoogleUser $googleUser */
                $googleUser = $client->fetchUserFromToken($accessToken);

                // Email ist die wichtigste Information
                $email = $googleUser->getEmail();

                // Prüfen, ob der User bereits existiert
                $existingUser = $this->userRepository->findOneBy(['email' => $email]);

                if ($existingUser) {
                    // User existiert bereits
                    if (!$existingUser->getGoogleId()) {
                        // Nur wenn der User noch nicht mit Google verbunden ist, setzen wir die Google-ID
                        $existingUser->setGoogleId($googleUser->getId());
                        $existingUser->setRegistrationSource('google');
                    }

                    // Hier: Immer die Benutzerdaten aktualisieren, unabhängig davon, ob die Google-ID bereits gesetzt war
                    $this->updateUserFromGoogleData($existingUser, $googleUser);
                    $this->entityManager->persist($existingUser);
                    $this->entityManager->flush();

                    return $existingUser;
                }

                // Neuen User erstellen
                $user = new User();
                $user->setEmail($email);
                $user->setGoogleId($googleUser->getId());
                $user->setRegistrationSource('google');
                $user->setPassword($password ?? '');
                $user->setRoles(['ROLE_USER']);
                $this->updateUserFromGoogleData($user, $googleUser);
                
                $this->entityManager->persist($user);
                $this->entityManager->flush();

                return $user;
            })
        );
    }

    private function updateUserFromGoogleData(User $user, GoogleUser $googleUser): void
    {
        // Name kann als "given_name" und "family_name" oder in "name" enthalten sein
        $user->setFirstName($googleUser->getFirstName());
        $user->setLastName($googleUser->getLastName());
        
        // Avatar-URL und Locale, falls verfügbar
        if (method_exists($googleUser, 'getAvatar')) {
            $user->setAvatarUrl($googleUser->getAvatar());
        }
        
        if (method_exists($googleUser, 'getLocale')) {
            $user->setLocale($googleUser->getLocale());
        }
    }

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
    {
        // Weiterleitung nach erfolgreicher Authentifizierung
        return new RedirectResponse($this->router->generate('app_homepage'));
    }

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
    {
        $message = strtr($exception->getMessageKey(), $exception->getMessageData());

        return new Response($message, Response::HTTP_FORBIDDEN);
    }
    
    public function start(Request $request, AuthenticationException $authException = null): Response
    {
        return new RedirectResponse(
            $this->router->generate('app_login'),
            Response::HTTP_TEMPORARY_REDIRECT
        );
    }
}

Passe die entsprechenden Routen an, falls sich diese von deinen unterscheiden.

* Werbung/Affiliate Link
CBD Premium Produkte

Controller für Google OAuth-Integration

Als weiteren wichtigen Schritt benötigen wir noch einen Controller:

php bin/console make:controller Google

Folgenden Code fügen wir in die GoogleController.php Datei:

<?php

namespace App\Controller;

use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;

class GoogleController extends AbstractController
{
    /**
     * Link zur Initiierung des OAuth-Flows mit Google
     */
    #[Route('/connect/google', name: 'connect_google')]
    public function connectAction(ClientRegistry $clientRegistry): RedirectResponse
    {
        // Weiterleitung zur Google Authorization URL
        return $clientRegistry
            ->getClient('google')
            ->redirect([
                'profile', 
                'email' // Die benötigten Scopes
            ]);
    }

    /**
     * Diese Route wird nach erfolgreicher Authentifizierung bei Google aufgerufen
     * Sie wird vom Google-Authenticator behandelt und nicht von dieser Methode
     */
    #[Route('/connect/google/check', name: 'connect_google_check')]
    public function connectCheckAction(Request $request, ClientRegistry $clientRegistry)
    {
        // Diese Methode wird nie aufgerufen, da der GoogleAuthenticator
        // die Anfrage abfängt und verarbeitet
        return $this->redirectToRoute('app_homepage');
    }
}

Passe auch hier die entsprechende Route an.

Security-Konfiguration anpassen

Es wird Zeit unseren GoogleAuthenticator zu integrieren. Dazu öffnen wir unsere security.yaml unter config/packages/security.yaml und fügen folgende Zeilen hinzu:

security:
    firewalls:
        main:
            # Google OAuth-Authenticator aktivieren
            custom_authenticators:
                - App\Security\GoogleAuthenticator

            entry_point: form_login

Google Login-Button

Im Login und Registrierungs-Template fügen wir dann noch den Button für die Google Authentifikation ein.

{# templates/security/login.html.twig #}
{# templates/registration/register.html.twig #}

<div class="text-center my-4">
    <a href="{{ path('connect_google') }}" class="btn btn-outline-danger w-100 mb-3 d-flex align-items-center justify-content-center">
         Mit Google anmelden
    </a>
</div>

Zusammenfassung der Google OAuth-Integration für Symfony

Wir haben jetzt eine vollständige Implementierung für die Google OAuth-Integration in deinem Symfony Projekt erstellt. Hier ist eine Übersicht der Implementierung:

Installierte Pakete

  • KnpUOAuth2ClientBundle für die OAuth2-Integration
  • League/OAuth2-Google als Google OAuth2 Provider

Hauptkomponenten

  1. User Entity mit Google-Unterstützung:
    • Speichert wichtige Google-Informationen wie googleId, Profilbild, Name
    • Unterstützt sowohl herkömmliche Passwort-Authentifizierung als auch Google OAuth
  2. GoogleAuthenticator:
    • Verarbeitet den Google OAuth-Flow
    • Erstellt neue Benutzer oder verbindet bestehende Konten
    • Übernimmt die Authentifizierung für die Security-Komponente
  3. Controller für Login und Google-Verbindung:
    • GoogleController mit Routen für OAuth-Initiierung und Callback
    • SecurityController für klassisches Login
    • RegistrationController für manuelle Registrierung
  4. Templates mit Google-Button:
    • Login- und Registrierungsseiten mit Google-Anmeldebutton

Funktionalitäten

  • Single Sign-On (SSO) mit Google:
    • Benutzer können sich mit einem Klick über ihren Google-Account anmelden
    • Profildaten werden aus dem Google-Konto übernommen
  • Automatisches Konto-Linking:
    • Wenn ein Benutzer mit der gleichen E-Mail-Adresse bereits existiert, wird sein Konto mit Google verknüpft
  • Hybride Authentifizierung:
    • Unterstützt sowohl herkömmliche E-Mail/Passwort-Authentifizierung als auch Google OAuth
    • Speichert die Registrierungsquelle (Google oder Formular)

Tipps für Produktionsumgebungen

  • Achte auf sichere HTTPS-Verbindungen
  • Stelle sicher, dass Weiterleitungs-URLs in der Google Cloud Console korrekt konfiguriert sind
  • Für hohe Benutzerzahlen (>100) ist eine vollständige Verifizierung des Google-Projekts erforderlich

Diese Implementierung ist zukunftssicher und kann einfach um weitere OAuth-Provider erweitert werden. Die Benutzerinformationen werden konsistent gespeichert, unabhängig davon, ob ein Benutzer sich über Google anmeldet oder traditionell registriert.

Hast du Fragen oder kommst an einer Stelle nicht weiter, schreibe deine Erfahrungen gerne in die Kommentare.

* Werbung/Affiliate Link
BISON Kryptowährungen

Schreibe einen Kommentar

Erforderliche Felder sind entsprechend markiert.

Wird nicht veröffentlicht.

Datenschutz
Programmier-Tipps - Programmieren lernen ist nicht schwer!

Wir verwenden Cookies, um unsere Webseite für Dich optimal zu gestalten, fortlaufend zu verbessern und die Zugriffe auf unsere Webseite zu analysieren. Cookie-Informationen werden in deinem Browser gespeichert und helfen uns zu verstehen, welche Abschnitte der Website für dich am interessantesten und nützlichsten sind. Genauere Informationen findest du in unserer Datenschutzerklärung.

Notwendige Cookies

Notwendige Cookies sollten jederzeit aktiviert sein, damit wir deine Einstellungen für die Cookie-Einstellungen speichern können. Details findest du in unserer Datenschutzerklärung.

Google AdSense

Diese Website benutzt Google AdSense, einen Dienst zum Einbinden von Werbeanzeigen der Google Inc. ("Google"). Google AdSense verwendet sogenannte „Cookies“, Textdateien, die auf Ihrem Computer gespeichert werden und die eine Analyse der Benutzung der Website ermöglichen. Genauere Informationen findest du in unserer Datenschutzerklärung.

Diesen Cookie aktiviert zu lassen, unterstützt uns ohne dass du Geld ausgeben musst.

Google Analytics

Diese Website nutzt den Webanalysedienst Google Analytics, der sogenannte Cookies einsetzt. Dies sind kleine Textdateien, die auf Ihrem Device gespeichert werden und eine Analyse der Website-Nutzung ermöglichen. Die erzeugten Informationen werden in der Regel an einen Server von Google in den USA übertragen und dort gespeichert. Weitere Informationen findest du in unserer Datenschutzerklärung.

Das aktivieren ermöglicht es uns unsere Webseite für dich noch attraktiver zu machen.