Ця публікація була натхненна цією чудовою середньою публікацією і може розглядатися як додаткова публікація, де вхід у Google реалізований у середовищі з окремим додатком React та API Laravel.
1. Створення проекту
Google Створіть новий проект Google тут: https://console.developers.google.com/projectcreate.
Після того, як проект створено, продовжуйте створювати новий "OAuth 2.0 Client ID".
Спочатку переконайтеся, що вибрано правильний проект, а потім перейдіть до налаштування екрана згоди, натиснувши кнопку
«НАЛАШТУВАТИ ЕКРАН ЗГОДИ».Для цього прикладу ми налаштуємо User Type як зовнішній.
Після того, як ви заповните решту форми (ви можете просто заповнити обов'язкові поля і залишити решту за замовчуванням), давайте нарешті створимо OAuth Client.
Виберіть «Веб-додаток» як тип програми та дайте їй зрозумілу назву.
Далі додайте «Авторизовані джерела JavasScript» та «Авторизовані URI перенаправлення». Оскільки ми будемо створювати React-додаток за допомогою npx create-react-app
і він запускає додаток за http://localhost:3000
замовчуванням, ми додамо його як авторизоване джерело. Наш URI перенаправлення буде маршрутом, тому ми додаємо абсолютну URL-адресу цього маршруту /auth/google
до "Authorized redirect URIs".
Після заповнення даних натисніть «Створити», і ви отримаєте облікові дані в модальному режимі. Запишіть їх або завантажте JSON, тому що вони нам знадобляться в налаштуваннях програми Laravel.
Ось і все. Давайте перейдемо до створення 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
Оскільки 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
ви повинні побачити щось подібне.
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 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.
Зовнішні ресурси
- Laravel Installation docs – https://laravel.com/docs/9.x/installation#choosing-your-sail-services
- Laravel Socialite – https://laravel.com/docs/9.x/socialite
- Laravel Sanctum, issuing API tokens – https://laravel.com/docs/9.x/sanctum#issuing-api-tokens
- React, installation – https://create-react-app.dev/docs/getting-started
- React, adding router – https://create-react-app.dev/docs/adding-a-router
Вам потрібна допомога з налаштуванням входу в Google за допомогою React та Laravel API?
Щодо всього, що пов'язано з розробкою Laravel, надішліть нам свій запит на адресу [email protected]!