💡

LaravelでサクっとはじめるGoogleログイン

2025/02/12に公開

はじめに

Laravel+Socialiteでgoogleログインを実装した時の手順を残しておきます。

バージョン情報

  • Laravel Framework 11.42.0
  • laravel/sail v1.41.0
  • laravel/socialite v5.18.0

下準備

Google Cloudの設定

Laravelで早速構築する前に以下の手順どおりGoogle Cloudでプロジェクトを作成しておきましょう
https://cloud.google.com/resource-manager/docs/creating-managing-projects?hl=ja#creating_a_project

プロジェクトを作成したらLaravelで使用するクライアントIDとクライアントシークレットを作成します
https://support.google.com/workspacemigrate/answer/9222992?hl=ja

承認済みのリダイレクトURIはアプリケーションのURL(http://localhost/auth/google/callbackなど)を指定しておきます

このURLは後でroutes/auth.phpに生やします

.envの設定

Google Cloudで取得した値を環境変数(.env)に追記しておきます

.env
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
GOOGLE_REDIRECT_URL=

laravelが環境変数の値を取得するためにconfig/services.phpに値を追加しておきます

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
database/migrations/2025_02_12_133941_modify_users_table.php
<?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
app/Http/Controllers/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に追記しますがゲストユーザでログインできる箇所であればどこでも構いません。

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
tests/Feature/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を提供しています。
https://developers.google.com/identity/branding-guidelines?hl=ja

おわりに

ソーシャルログインもLaravelであればサクッと実装することができます。
今回はGoogleログインを例にあげましたがSocialiteではLINEなども対応しており、ぜひとも遊んでみたいところです

Discussion