LaravelでサクっとはじめるGoogleログイン
はじめに
Laravel+Socialiteでgoogleログインを実装した時の手順を残しておきます。
バージョン情報
- Laravel Framework 11.42.0
- laravel/sail v1.41.0
- laravel/socialite v5.18.0
下準備
Google Cloudの設定
Laravelで早速構築する前に以下の手順どおりGoogle Cloudでプロジェクトを作成しておきましょう
プロジェクトを作成したらLaravelで使用するクライアントIDとクライアントシークレットを作成します
承認済みのリダイレクトURIはアプリケーションのURL(http://localhost/auth/google/callback
など)を指定しておきます
このURLは後でroutes/auth.php
に生やします
.envの設定
Google Cloudで取得した値を環境変数(.env
)に追記しておきます
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_REDIRECT_URL=
laravelが環境変数の値を取得するためにconfig/services.php
に値を追加しておきます
'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_REDIRECT_URL'),
],
Socialiteのインストール
laravelにsocialiteをインストールします
sail composer require laravel/socialite
usersテーブルのマイグレーション
今回、既存のメールアドレス+パスワード認証に加えてGoogleログイン機能を追加することになりました。
Googleログインで登録されたユーザーの初期状態はメールアドレス+パスワード認証できない仕様にします。
sail artisan make:migration modify_users_table --table=users
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
public function up(): void
{
Schema::table('users', function (Blueprint $table) {
$table->string('google_id')->nullable();
$table->string('password')->nullable(true)->change();
});
}
public function down(): void
{
Schema::table('users', function (Blueprint $table) {
$table->dropColumn('google_id');
$table->string('password')->nullable(false)->change();
});
}
};
passwordにnullが入ることで、googleアカウント連携でアカウント登録したユーザーはメールアドレス+パスワード認証できない状態になります。
ログイン後はユーザーがパスワードを設定できる機能を追加すればメールアドレス+パスワード認証もできるし、googleアカウント連携でパスワード無しで認証することもできるようになります。
作成したら実行しておきましょう
sail artisan migrate
コントローラの実装
Googleログインを処理するコントローラを作ります
sail artisan make:controller Auth/GoogleLoginController
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
use App\Models\User;
class GoogleLoginController extends Controller
{
/**
* ユーザーをGoogleの認証ページにリダイレクトする
*/
public function redirectToGoogle()
{
return Socialite::driver('google')->redirect();
}
/**
* 認証後にGoogleからのコールバックを受信する
*/
public function handleGoogleCallback()
{
$google_account = Socialite::driver('google')->user();
$user = User::updateOrCreate([
'google_id' => $google_account->getId(),
],[
'email' => $google_account->getEmail(),
'name' => $google_account->getName(),
'email_verified_at' => now(), // メール認証がある場合のみ
]);
Auth::login($user);
return to_route('home');
}
}
redirectToGoogle
でユーザーをGoogleアカウントとの連携画面に飛ばし、ユーザーが連携を承認した場合handleGoogleCallback
でユーザーのGoogleアカウント情報を取得することができます。
$google_account->getId()
で取得できるIDはGoogleアカウントの識別子となるので、その値をキーにしてupdateOrCreate
します。
メールアドレス+パスワード認証時にメールアドレス認証をしている場合はGoogleログインで代替できるのでemail_verified_at
に値を入れておきましょう。
ルーティングの実装
前工程で作成したコントローラに飛ばすルートを作成します。
ここではroutes/auth.php
に追記しますがゲストユーザでログインできる箇所であればどこでも構いません。
<?php
use App\Http\Controllers\Auth\GoogleLoginController;
Route::middleware('guest')->group(function () {
// 通常のアカウント登録等の処理が入る...
Route::get('auth/google', [GoogleLoginController::class, 'redirectToGoogle'])
->name('auth.google');
Route::get('auth/google/callback', [GoogleLoginController::class, 'handleGoogleCallback'])
->name('auth.google.callbck');
});
テストで動作確認
コントローラとルートを作成できたので、動くかどうかテストしてみます。
sail artisan make:test Auth/GoogleLoginControllerTest
<?php
namespace Tests\Feature\Controllers\Auth;
use Carbon\Carbon;
use Illuminate\Http\RedirectResponse;
use Laravel\Socialite\Facades\Socialite;
use Mockery;
use Tests\TestCase;
class GoogleLoginControllerTest extends TestCase
{
/**
* @test
*/
public function Google連携画面にリダイレクトする(): void
{
$driver = Mockery::mock('Laravel\Socialite\Two\GoogleProvider');
$driver->shouldReceive('redirect')
->andReturn(new RedirectResponse('http://localhost:8080/auth/google/callback'));
Socialite::shouldReceive('driver')->with('google')->andReturn($driver);
$this->get('/auth/google')
->assertStatus(302)
->assertRedirect('http://localhost:8080/auth/google/callback');
}
/**
* @test
*/
public function Googleアカウント情報をユーザー登録する()
{
$socialite_user = Mockery::mock('Laravel\Socialite\Two\User');
$socialite_user
->shouldReceive('getId')->andReturn($google_id = fake()->unique()->randomNumber)
->shouldReceive('getName')->andReturn($user_name = fake()->name)
->shouldReceive('getEmail')->andReturn($user_email = fake()->unique()->safeEmail);
$now = Carbon::now();
Carbon::setTestNow($now);
Socialite::shouldReceive('driver->user')->andReturn($socialite_user);
// リダイレクトしているか
$this->get('/auth/google/callback')
->assertStatus(302)
->assertRedirect(route('home'));
// ログインしているか
$this->assertAuthenticated();
// ユーザー登録しているか
$this->assertDatabaseHas('users', [
'google_id' => $google_id,
'name' => $user_name,
'email' => $user_email,
'email_verified_at' => $now,
]);
}
}
実際にGoogleCloudに飛ばされるとまずいのでSocialiteはモックしています。
テストを実行してPASSすれば成功です。
sail artisan test tests/Feature/Auth/GoogleLoginControllerTest.php
最後に画面を追加する
あとはフロントエンド側で前工程で作成したルートに飛ぶリンクを作成すれば完了です。
ログイン画面とユーザー登録画面にそれぞれあればいいでしょう。
よくみるアカウント連携ボタンはGoogleがHTMLとCSSを提供しています。
おわりに
ソーシャルログインもLaravelであればサクッと実装することができます。
今回はGoogleログインを例にあげましたがSocialiteではLINEなども対応しており、ぜひとも遊んでみたいところです
Discussion