• Час читання ~7 хв
  • 15.01.2024

Ця публікація була натхненна цією чудовою середньою публікацією і може розглядатися як додаткова публікація, де вхід у Google реалізований у середовищі з окремим додатком React та API Laravel.

1. Створення проекту

Google Створіть новий проект Google тут: https://console.developers.google.com/projectcreate.

Creating new project - React Laravel API
Creating new project “React Laravel API”

Після того, як проект створено, продовжуйте створювати новий "OAuth 2.0 Client ID".

Спочатку переконайтеся, що вибрано правильний проект, а потім перейдіть до налаштування екрана згоди, натиснувши кнопку

Correct project selected and configure consent button
Correct project selected and configure consent button

«НАЛАШТУВАТИ ЕКРАН ЗГОДИ».Для цього прикладу ми налаштуємо User Type як зовнішній.

Google OAuth consent screen configuration
OAuth consent screen configuration

Після того, як ви заповните решту форми (ви можете просто заповнити обов'язкові поля і залишити решту за замовчуванням), давайте нарешті створимо OAuth Client.

Creating new OAuth client ID
Creating new OAuth client ID

Виберіть «Веб-додаток» як тип програми та дайте їй зрозумілу назву.

Application type and Name
Application type and Name

Далі додайте «Авторизовані джерела JavasScript» та «Авторизовані URI перенаправлення». Оскільки ми будемо створювати React-додаток за допомогою npx create-react-app і він запускає додаток за http://localhost:3000 замовчуванням, ми додамо його як авторизоване джерело. Наш URI перенаправлення буде маршрутом, тому ми додаємо абсолютну URL-адресу цього маршруту /auth/google до "Authorized redirect URIs".

JavasScript origin and Authorized redirect URI
JavasScript origin and Authorized redirect URI

Після заповнення даних натисніть «Створити», і ви отримаєте облікові дані в модальному режимі. Запишіть їх або завантажте JSON, тому що вони нам знадобляться в налаштуваннях програми Laravel.

Client details
Client details

Ось і все. Давайте перейдемо до створення Laravel API.

2. Створення Laravel API

2.1. Встановлення та налаштування Laravel та необхідних пакетів

Для початку давайте створимо новий додаток Laravel. У MacOS ви можете виконати наступну команду, щоб встановити нову програму Laravel у папку "laravel" за допомогою Laravel Sail (mysql).

curl -s "https://laravel.build/laravel?with=mysql" | bash

Як запропоновано в кінці команди, запустіть

cd laravel && ./vendor/bin/sail up

Якщо все пройшло добре, ваша програма має бути запущена .http://localhost

http://localhost - Fresh Laravel installation
http://localhost

Оскільки Laravel тепер поставляється з Laravel Sanctum за замовчуванням, ми будемо використовувати його для автентифікації запитів API. Однак, перш ніж ми зможемо випустити API-токен для користувача, ми повинні "Увійти" через Google. Для цього ми будемо використовувати Laravel Socialite, тому давайте продовжимо його додавати.

composer require laravel/socialite

Щоб завершити налаштування, нам потрібно налаштувати config/services.php файл і додати змінні env.

// config/services.php
return [
    ...
    'google' => [
        'client_id' => env('GOOGLE_CLIENT_ID'),
        'client_secret' => env('GOOGLE_CLIENT_SECRET'),
        'redirect' => env('GOOGLE_REDIRECT_URI'),
    ],
];

GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET you got in the last step of “Creating Google project” part. GOOGLE_REDIRECT_URI is the same as the one you configured in “Authorized Redirect URI” in Google project. This points to React App!!

// .env
GOOGLE_CLIENT_ID=783523056435-2901krcqpbe6a08q0gls6ifvha8lrd10.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=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
GOOGLE_REDIRECT_URI=http://localhost:3000/auth/google

2.2. Коригування міграції та моделей

Далі налаштуємо міграцію за замовчуванням. Зазвичай ми додаємо нову міграцію, але оскільки ми все ще не перенесли базу даних, ми можемо просто змінити міграцію за замовчуванням. У цьому прикладі ми додамо 2 поля. Перше – обов'язкове поле, де буде зберігатися ідентифікатор користувача, а друге – необов'язкове avatar полеgoogle_id. Ви можете перевірити й зберегти будь-яке інше поле, яке Google повертає відповідно до ваших уподобань.

// database/migrations/2014_10_12_000000_create_users_table.php
public function up()
{
    Schema::create('users', function (Blueprint $table) {
        $table->id();
        $table->string('name');
        $table->string('email')->unique();
        $table->timestamp('email_verified_at')->nullable();
        $table->string('password')->nullable(); // Changed to nullable()
        $table->string('google_id'); // Added
        $table->string('avatar')->nullable(); // Added
        $table->rememberToken();
        $table->timestamps();
    });
}

І тепер ми готові перенести базу даних, щоб ви могли виконати наступне, щоб запустити міграції з Sail.

 ./vendor/bin/sail artisan migrate

Крім того, не забудьте відобразити зміни в моделі користувача.

// app/Models/User.php
protected $fillable = [
    'name',
    'email',
    'email_verified_at', // Fillable since we will manually add it on Sign on
    'password',
    'google_id', // Added
    'avatar', // Added
];

2.3. Додавання маршрутів та логіки контролера.

По-перше, нам знадобляться 2 нових маршрути в routes/api.php.

// routes/api.php
use App\Http\Controllers\AuthController;
Route::get('auth', [AuthController::class, 'redirectToAuth']);
Route::get('auth/callback', [AuthController::class, 'handleAuthCallback']);

redirectToAuth method is straight forward. It just generates Google redirect url and returns it. Make sure you use stateless() since we are using this Laravel app as API and we are not keeping state at any time.

// app/Http/Controllers/AuthController.php
<?php
namespace App\Http\Controllers;
use App\Models\User;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Http\JsonResponse;
use Laravel\Socialite\Contracts\User as SocialiteUser;
use Laravel\Socialite\Facades\Socialite;
class AuthController extends Controller
{
    public function redirectToAuth(): JsonResponse
    {
        return response()->json([
            'url' => Socialite::driver('google')
                         ->stateless()
                         ->redirect()
                         ->getTargetUrl(),
        ]);
    }
}

handleAuthCallback contains the logic to handle the callback. To keep it simple, we will just check if user is correctly authenticated, firstOrCreate the User and respond with the User and newly generated bearer token. Tokens are generated with Laravel Sanctum $user->createToken('google-token')->plainTextToken.

У звичайному випадку використання, ймовірно, буде або повторно використано маркер автентифікації, або скасовано попередні, але це залежить від вас, а не в рамках цього прикладу.

// app/Http/Controllers/AuthController.php
<?php
namespace App\Http\Controllers;
use App\Models\User;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Http\JsonResponse;
use Laravel\Socialite\Contracts\User as SocialiteUser;
use Laravel\Socialite\Facades\Socialite;
class AuthController extends Controller
{
    public function handleAuthCallback(): JsonResponse
    {
        try {
            /** @var SocialiteUser $socialiteUser */
            $socialiteUser = Socialite::driver('google')->stateless()->user();
        } catch (ClientException $e) {
            return response()->json(['error' => 'Invalid credentials provided.'], 422);
        }
        /** @var User $user */
        $user = User::query()
            ->firstOrCreate(
                [
                    'email' => $socialiteUser->getEmail(),
                ],
                [
                    'email_verified_at' => now(),
                    'name' => $socialiteUser->getName(),
                    'google_id' => $socialiteUser->getId(),
                    'avatar' => $socialiteUser->getAvatar(),
                ]
            );
        return response()->json([
            'user' => $user,
            'access_token' => $user->createToken('google-token')->plainTextToken,
            'token_type' => 'Bearer',
        ]);
    }
}

Ось і все. Ви можете знайти весь цей приклад з тестами в цьому репозиторії GitHub.

3. Створення React App

3.1 Встановлення React app

Давайте спочатку створимо новий додаток React за допомогою npx.

npx create-react-app react-app
cd react-app
npm start

Якщо все пройшло добре, то при відвідуванні http://localhost:3000ви повинні побачити щось подібне.

http://localhost:3000 - Fresh React installation
http://localhost:3000

3.2. Додавання react-router-dom та налаштування маршрутів

Для простоти додамо ще react-router-domй .

npm install --save react-router-dom

Тепер ми можемо налаштувати наші маршрути у App.js файлі.

// src/App.js
import './App.css';
import {Route, BrowserRouter, Routes} from "react-router-dom";
import SignIn from "./SignIn";
import GoogleCallback from "./GoogleCallback";
function App() {
  return (
      <BrowserRouter>
          <Routes>
              <Route path="/" element={<SignIn />}></Route>
              <Route path="/auth/google" element={<GoogleCallback />}></Route>
          </Routes>
      </BrowserRouter>
  );
}
export default App;

3.3. Отримання URL-адреси редиректу Google і перенаправлення на спів у формі

SignIn component is simple. On load, we will fetch Google redirect url from Laravel API and set it as href for our link.

// src/SignIn.js
import React, {useState, useEffect} from 'react';
function SignIn() {
    const [loginUrl, setLoginUrl] = useState(null);
    useEffect(() => {
        fetch('http://localhost:80/api/auth', {
            headers : {
                'Content-Type': 'application/json',
                'Accept': 'application/json'
            }
        })
            .then((response) => {
                if (response.ok) {
                    return response.json();
                }
                throw new Error('Something went wrong!');
            })
            .then((data) => setLoginUrl( data.url ))
            .catch((error) => console.error(error));
    }, []);
    return (
        <div>
            {loginUrl != null && (
                <a href={loginUrl}>Google Sign In</a>
            )}
        </div>
    );
}
export default SignIn;

Коли користувач натискає на посилання "Google Sign In", сторінка перенаправляється на форму аутентифікації Google.

Google Sign In form
Google Sign In form

Після успішної автентифікації за допомогою облікового запису Google Google перенаправить назад на URL-адресу, яку ми налаштували в змінній GOOGLE_REDIRECT_URI .env додатку Laravel, з деякими додатковими даними в search параметрах.

3.4. Обробка зворотного зворотного виклику та аутентифікація запитів

користувачів У нашому другому компоненті , GoogleCallbackми візьмемо ці search параметри та "проксі" їх до Laravel API. Якщо все піде добре, Laravel відповість новоствореним/отриманим користувачем і новим токеном авторизації на пред'явника, який ми зможемо використовувати для здійснення автентифікованих викликів до захищених маршрутів Laravel API sanctum.

// src/GoogleCallback.js
import React, {useState, useEffect} from 'react';
import {useLocation} from "react-router-dom";
function GoogleCallback() {
    const [loading, setLoading] = useState(true);
    const [data, setData] = useState({});
    const [user, setUser] = useState(null);
    const location = useLocation();
    // On page load, we take "search" parameters 
    // and proxy them to /api/auth/callback on our Laravel API
    useEffect(() => {
        fetch(`http://localhost:80/api/auth/callback${location.search}`, {
            headers : {
                'Content-Type': 'application/json',
                'Accept': 'application/json'
            }
        })
            .then((response) => {
                return response.json();
            })
            .then((data) => {
                setLoading(false);
                setData(data);
            });
    }, []);
    // Helper method to fetch User data for authenticated user
    // Watch out for "Authorization" header that is added to this call
    function fetchUserData() {
        fetch(`http://localhost:80/api/user`, {
            headers : {
                'Content-Type': 'application/json',
                'Accept': 'application/json',
                'Authorization': 'Bearer ' + data.access_token,
            }
        })
            .then((response) => {
                return response.json();
            })
            .then((data) => {
                setUser(data);
            });
    }
    if (loading) {
        return <DisplayLoading/>
    } else {
        if (user != null) {
            return <DisplayData data={user}/>
        } else {
            return (
                <div>
                    <DisplayData data={data}/>
                    <div style={{marginTop:10}}>
                        <button onClick={fetchUserData}>Fetch User</button>
                    </div>
                </div>
            );
        }
    }
}
function DisplayLoading() {
    return <div>Loading....</div>;
}
function DisplayData(data) {
    return (
        <div>
            <samp>{JSON.stringify(data, null, 2)}</samp>
        </div>
    );
}
export default GoogleCallback;

Ось і все! Тепер у вас є повнофункціональний вхід у Google за допомогою React і Laravel API.

Ви можете знайти весь проект у цьому репозиторії GitHub.

Зовнішні ресурси

  1. Laravel Installation docs – https://laravel.com/docs/9.x/installation#choosing-your-sail-services
  2. Laravel Socialite – https://laravel.com/docs/9.x/socialite
  3. Laravel Sanctum, issuing API tokens – https://laravel.com/docs/9.x/sanctum#issuing-api-tokens
  4. React, installation – https://create-react-app.dev/docs/getting-started
  5. React, adding router – https://create-react-app.dev/docs/adding-a-router

Вам потрібна допомога з налаштуванням входу в Google за допомогою React та Laravel API?
Щодо всього, що пов'язано з розробкою Laravel, надішліть нам свій запит на адресу [email protected]!

Comments

No comments yet
Yurij Finiv

Yurij Finiv

Full stack

Про мене

Professional Fullstack Developer with extensive experience in website and desktop application development. Proficient in a wide range of tools and technologies, including Bootstrap, Tailwind, HTML5, CSS3, PUG, JavaScript, Alpine.js, jQuery, PHP, MODX, and Node.js. Skilled in website development using Symfony, MODX, and Laravel. Experience: Contributed to the development and translation of MODX3 i...

Про автора CrazyBoy49z
WORK EXPERIENCE
Контакти
Ukraine, Lutsk
+380979856297