Logowanie za pomocą Facebooka i Google przy użyciu Laravel Socialite

Paweł Mysior
1 sierpnia 2018

W dzisiejszych czasach wiele aplikacji oferuje użytkownikom możliwość zalogowania się za pomocą ich kont w popularnych serwisach społecznościowych takich jak Facebook. Dzięki oficjalnej paczce Laravel Socialite dodanie takiej możliwości do aplikacji napisanej w Laravelu jest bardzo proste.

W tym wpisie postawimy od zera aplikację Laravela, w której oprócz rejestracji i logowania za pomocą adresu e-mail i hasła pozwolimy użytkownikom rejestrować i logować się za pomocą ich konta Facebook i/lub Google.

Laravel new

Zacznijmy od utworzenia nowej aplikacji Laravela za pomocą instalatora:

laravel new laravel-socialite-example

W celu rejestrowania użytkowników, będziemy potrzebowali bazy danych. Utwórzmy bazę danych laravel-socialite-example i ustawmy parametry dostępu do niej w pliku .env. Ja używam Laravel Valet, w związku z czym bazę tworzę bezpośrednio na swoim komputerze. Moje parametry wyglądają tak:

DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel-socialite-example
DB_USERNAME=root
DB_PASSWORD=

Zmigrujmy naszą bazę danych:

php artisan migrate

Następnie użyjmy komendy php artisan make:auth w celu wygenerowanie ścieżek, kontrolerów i widoków potrzebnych do obsługi standardowej rejestracji i logowania. Użyjmy komendy php artisan serve, żeby odpalić lokalny serwer PHP i odwiedźmy naszą stronę w przeglądarce pod adresem http://localhost:8000. Spróbujmy się zarejestrować:

register

post-register

Jeśli wszystko działa, przejdźmy do zainstalowania i konfiguracji Socialite.

Laravel Socialite

Dodajmy Socialite do naszego projektu za pomocą komendy:

composer require laravel/socialite

Klucze konfiguracyjne od Facebooka i Google

Zanim użyjemy w aplikacji Socialite, musimy uzyskać i dodać klucze konfiguracyjne od dostawców (Facebook i Google). Zacznijmy od dodania do tablicy w pliku config/services.php dwóch wpisów:

'facebook' => [
    'client_id' => env('FACEBOOK_CLIENT_ID'),
    'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
    'redirect' => '/login/facebook/callback',
],

'google' => [
    'client_id' => env('GOOGLE_CLIENT_ID'),
    'client_secret' => env('GOOGLE_CLIENT_SECRET'),
    'redirect' => '/login/google/callback',
],

Używamy tutaj funkcji globalnej env(), która pobiera klucze z pliku .env znajdującego się w głównym katalogu naszej aplikacji. Dodajmy w nim potrzebne klucze:

FACEBOOK_CLIENT_ID=
FACEBOOK_CLIENT_SECRET=

GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=

Warto też dodać odpowiadające klucze w pliku .env.example. Ten plik, w przeciwieństwie do pliku .env, powinien być zapisywany do repozytorium. Jest on swego rodzaju instrukcją, informującą jakie klucze powinny się znaleźć w pliku .env.

W polu redirect ustawiamy adres, pod który Facebook i Google mają wrócić, gdy użytkownik się już zaloguje. Możemy tutaj użyć ścieżki względnej, Socialite sam utworzy z tego pełny adres URL.

Następnym krokiem jest zdobycie kluczy client_idclient_secret od Facebooka i Google.

Zacznijmy od Facebooka. Przejdźmy do tego linku: https://developers.facebook.com/ i wykonajmy po kolei kroki grafiki znajdującej się pod tym linkiem: instrukcja dla Facebooka.

W pliku .env przypiszmy wartość z pola App ID do klucza FACEBOOK_CLIENT_ID, a wartość z pola App Secret do klucza FACEBOOK_CLIENT_SECRET.

Teraz przejdźmy do procesu uzyskania kluczy od Google. Przejdźmy do tego linku: https://console.developers.google.com/projectcreate. Uzyskanie kluczy wymaga stworzenia nowego projektu, włączenia interfejsu Google+ API i utworzenie danych logowania. Jest z tym trochę roboty, a interfejs Google Console nie jest zbyt przyjazny, dlatego podobnie jak w przypadku Facebooka, stworzyłem grafikę, która przedstawia w kolejnych screenshotach jak uzyskać te klucze: instrukcja dla Google.

W pliku .env przypiszmy wartość z pola Identyfikator klienta do klucza GOOGLE_CLIENT_ID a wartość z pola Tajny klucz klienta do klucza GOOGLE_CLIENT_SECRET.

Ważna uwaga: przy ustawianiu konfiguracji Facebooka pomineliśmy ustawienie URI przekierowania, które ustawiliśmy przy okazji konfiguracji Google. Wygląda na to, że gdy przekierowujemy do Facebooka z adresu http://localhost:8000, nie ma to znaczenia. Przed opublikowaniu aplikacji, będziemy jednak musieli ustawić poprawny adres w polu Valid OAuth Redirect URIs w panelu ustawień Facebook Login.

Ok, klucze mamy ustawione, jesteśmy gotowi do logowania użytkowników.

Ścieżki Socialite

Żeby obsłużyć proces logowania za pomocą Socialite, potrzebujemy dwóch ścieżek. Jednej, która przekieruje użytkownika do dostawcy i drugiej, do której użytkownik wróci po zalogowaniu się za pomocą swojego konta u dostawcy. Dodajmy w plik routes/web.php następujące ścieżki:

Route::get('login/{provider}', 'Auth\LoginController@redirectToProvider');
Route::get('login/{provider}/callback', 'Auth\LoginController@handleProviderCallback');

Następnie dodajmy odpowiadające im metody w pliku app/Http/Controllers/Auth/LoginController:

/**
* @param  $provider
* @return \Illuminate\Http\Response
*/
public function redirectToProvider($provider)
{
    return Socialite::driver($provider)->redirect();
}

/**
* @param  $provider
* @return \Illuminate\Http\Response
*/
public function handleProviderCallback($provider)
{
    $user = Socialite::driver($provider)->user();

    dd($user);
}

Pamiętajmy by na górze pliku zaimportować Socialite: use Laravel\Socialite\Facades\Socialite;.

Używamy tutaj dwóch metod fasady Socialite. Metoda redirect() Socialite wysyła użytkownika do dostawcy, metoda user() zwraca dane użytkownika po powrocie od dostawcy.

To tyle jeśli chodzi o konfiguracje Socialite. Nasza aplikacja przekierowuje poprawnie użytkownika do Facebooka lub Google i potrafi odebrać dane o użytkowniku z powrotem. Następnym krokiem jest zarejestrowanie lub zalogowanie użytkownika, na podstawie tych danych.

Modyfikacja migracji tabeli users

Zacznijmy od modyfikacji naszej tabeli users. Dodajmy pole facebook_id oraz google_id, w których będziemy zapisywać id użytkownika w systemie dostawcy. Jako, że użytkownik będzie się rejestrować za pomocą tylko jednego z dwóch dostawców, oba te pola muszą być nullable. Oba powinny też być unikalne. Powinniśmy też zmienić definicję pól email oraz password. Oba te pola będą musiałby być nullable. Zmodyfikujmy treść metody up() w pliku database/migrations/2014_10_12_000000_create_users_table.php w następujący sposób:

public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->increments('id');
        $table->string('facebook_id')->nullable()->unique();
        $table->string('google_id')->nullable()->unique();
        $table->string('name');
        $table->string('email')->nullable()->unique();
        $table->string('password')->nullable();
        $table->rememberToken();
        $table->timestamps();
    });
}

Ważna uwaga: Facebook pozwala rejestrować się bez użycia adresu email. Dlatego niektórzy użytkownicy, po zalogowaniu się na Facebooku, wrócą do naszej aplikacji bez pola email. Bierzemy to pod uwagę i dlatego ustawiamy pole email jako nullable.

Nie zapomnijmy dodać pól facebook_idgoogle_id do tablicy przypisanej do pola $fillable w naszym modelu User:

// app/User.php

protected $fillable = [
    'name', 'email', 'password', 'facebook_id', 'google_id',
];

Zalogowanie lub zarejestrowanie użytkownika

Ostatnim etapem jest zarejestrowanie lub zalogowanie użytkownika na podstawie danych od dostawcy. Ten proces najłatwiej będzie wytłumaczyć patrząc na kod:

/**
* @param  $provider
* @return \Illuminate\Http\Response
*/
public function handleProviderCallback($provider)
{
    $socialiteUser = Socialite::driver($provider)->user();

    // Znajdź lub stwórz użytkownika na podstawie danych do dostawcy
    $user = $this->firstOrCreateUser($socialiteUser, $provider);

    // Zaloguj uzyskanego użytkownika
    Auth::login($user);

    // Przekieruj użytkownika tam gdzie chciał się dostać lub do domyślnej ścieżki
    return redirect()->intended($this->redirectPath());
}

/**
* @param  $socialiteUser
* @param  $provider
* @return \App\User
*/
protected function firstOrCreateUser($socialiteUser, $provider)
{
    // Jeśli istnieje użytkownik o podanym facebook_id
    // lub google_id, zwróć tego użytkownika
    if ($user = User::where("{$provider}_id", $socialiteUser->getId())->first()) {
        return $user;
    }

    // Jeśli istnieje użytkownik o podanym adresie e-mail przypisz facebook_id
    // lub google_id do jego konta, a następnie zwróc tego użytkownika
    if (!is_null($socialiteUser->getEmail()) && $user = User::where('email', $socialiteUser->getEmail())->first()) {
        $user->update(["{$provider}_id" => $socialiteUser->getId()]);

        return $user;
    }

    // Jeśli powyższe warunki nie zostały spełnione, to mamy do czynienia
    // z rejestracją, więc utwórz nowego użytkownika na podstawie 
    // danych od dostawcy i zwróc tego użytkownika
    return User::create([
        "{$provider}_id" => $socialiteUser->getId(),
        'email' => $socialiteUser->getEmail(),
        'name' => $socialiteUser->getName(),
    ]);
}

Na górze pliku zaimportujmy model User i fasadę Auth:

use App\User;
use Illuminate\Support\Facades\Auth;

W metodzie firstOrCreateUser() w pierwszej kolejności szukamy w naszej bazie użytkownika po polu facebook_id lub google_id. Jeśli go znajdziemy, to znaczy że użytkownik już się wcześniej zarejestrował za pomocą danego dostawcy. Zwracamy znalezionego użytkownika.

Jeśli ten warunek nie został spełniony to przechodzimy do następnego warunku. Sprawdzamy czy dostawca zwrócił adres e-mail. Jeśli tak, to szukamy w naszej bazie użytkownika po polu email. Jeśli go znajdziemy, to znaczy że użytkownik już się wcześniej zarejestrował za pomocą innego dostawcy lub "ręcznie" za pomocą loginu i hasła. W takim przypadku przypisujemy facebook_id lub google_id do jego konta, by mógł w przyszłości używać danego dostawcy i zwracamy znalezionego użytkownika.

Jeśli żaden z powyższych warunków też nie został spełniony, to znaczy nie znaleźliśmy użytkownika po żadnym z pól facebook_id, google_id ani email to znaczy, że mamy do czynienia z nowym użytkownikiem. Wykorzystujemy dane od dostawcy by stworzyć użytkownika i zwracamy go.

W metodzie handleProviderCallback() dostajemy użytkownika z metody firstOrCreateUser() i logujemy go za pomocą metody login() fasady Auth. Następnie używamy kodu return redirect()->intended($this->redirectPath());, żeby przekierować użytkownika tam gdzie chciał się dostać zanim przeszedł do ekranu logowania za pomocą metody intended(). Jako jej parametr podajemy domyślną ścieżkę, która zostanie używa, jeśli użytkownik po prostu przeszedł do ekranu logowania.

Dodajmy jeszcze przyciski w widoku logowania:

// resources/views/auth/login.blade.php

<div class="form-group row mb-0">
    <div class="col-md-8 offset-md-4">
        <a href="/login/google" class="btn btn-outline-primary">
            Zaloguj się przez Google
        </a>

        <a href="/login/facebook" class="btn btn-outline-primary">
            Zaloguj się przez Facebook
        </a>
    </div>
</div>

Oraz w widoku rejestracji:

// resources/views/auth/register.blade.php

<div class="form-group row mb-0">
    <div class="col-md-8 offset-md-4">
        <a href="/login/google" class="btn btn-outline-primary">
            Zarejestruj się przez Google
        </a>

        <a href="/login/facebook" class="btn btn-outline-primary">
            Zarejestruj się przez Facebook
        </a>
    </div>
</div>

To wszystko, od terazu użytkownicy mogą się w naszej aplikacji rejestrować i logować za pomocą swoich kont na Facebooku i Google.

Warto jeszcze dodać, że Socialite oficjalnie obsługuje logowanie za pomocą następujących serwisów: Facebook, Google, Twitter, Linkedin, Github i Bitbucket. Nieoficjalna lista innych wspieranych serwisów znajduje się tutaj: https://github.com/SocialiteProviders/Providers.

Jeśli macie jakieś wątpliwości, pytania lub problemy - piszcie w komentarzach!

Wygodny hosting zapewnia duet DigitalOceanLaravel Forge.
Copyright © laravelpolska.com

Drogi Użytkowniku!

Dalsze korzystanie z serwisu bez zmiany ustawień dotyczących cookies w przeglądarce oznacza akceptację plików cookies, co będzie skutkowało zapisywaniem ich na Twoich urządzeniach przez serwis internetowy laravelpolska.com. Jeśli nie wyrażasz zgody na przyjmowanie cookies, prosimy o zmianę ustawień w przeglądarce lub o opuszczenie serwisu. więcej

Stosujemy pliki cookies (tzw. ciasteczka) i inne pokrewne technologie, które mają na celu:

  • dostosowanie zawartości stron internetowych Serwisu do Twoich preferencji oraz optymalizacji korzystania ze stron internetowych; w szczególności pliki te pozwalają rozpoznać Twoje urządzenie i odpowiednio wyświetlić stronę internetową, dostosowaną do Twoich indywidualnych potrzeb;
  • utrzymanie Twojej sesji w Serwisie (po zalogowaniu), dzięki czemu nie musisz na każdej podstronie Serwisu ponownie wpisywać loginu i hasła,
  • zapewnienie bezpieczeństwa podczas korzystania z Serwisu,
  • ulepszenie świadczonych przez nas usług poprzez wykorzystanie danych w celach analitycznych i statystycznych,
  • poznanie Twoich preferencji na podstawie sposobu korzystania z naszych serwisów.

Wykorzystanie cookies pozwala nam zapewnić maksymalną wygodę przy korzystaniu z naszego Serwisu poprzez zapamiętanie Waszych preferencji i ustawień na naszych stronach. Więcej informacji o zamieszczanych plikach cookie oraz o możliwości zmiany ustawień przeglądarki oraz polityce przetwarzania danych znajdziesz w polityce prywatności.

Masz możliwość samodzielnej zmiany ustawień dotyczących cookies w swojej przeglądarce internetowej. Z poziomu przeglądarki internetowej, z której korzystasz, możliwe jest zarządzanie plikami cookies. W najpopularniejszych przeglądarkach istnieje m.in. możliwość:

  • zaakceptowania obsługi cookies, co pozwala na pełne korzystanie z opcji oferowanych przez witryny internetowe;
  • zarządzania plikami cookies na poziomie pojedynczych, wybranych przez użytkownika witryn;
  • określania ustawień dla różnych typów plików cookies, na przykład akceptowania plików stałych, jako sesyjnych itp.;
  • blokowania lub usuwania cookies.

Akceptuję pliki cookies