簡単な手順で構築する！ Laravel SailとGoogleログインの実装手法解説

# 概要
本記事では、Laravelを使用してGoogleログイン機能を実装する手順を解説します。Googleログインを組み込むことで、ユーザーはGoogleアカウントを使用して簡単にログインできるようになります。

# 所要時間
1時間

# 環境
Mac OS Venture
PHP 8.2.6
Laravel 10.12.0
Breeze 1.21
Socialite 5.6

# 流れ&学べること
1. Dockerを使用してLaravelの開発環境をセットアップする方法
2. Laravel Breezeを使用してログイン機能を追加する方法
3. Laravel Socialiteを使用してGoogleログイン機能を追加する方法


# Dockerインストールしていない方用
Dockerないよ！って人は、まずインストールしてください

https://www.docker.com/products/docker-desktop/

Macの方で、Homebrewで管理してる方は、以下でインストールできます
```zsh:zsh
brew install --cask docker
```
ちなみにDockerはLinux環境で動くので、Windowsの方はDockerを入れる前にWSLを入れる必要があります

# Laravel Sail
## Sailとは？
一言で言うと「Laravelの環境構築をしてくれるツール」です
なので、ポチポチするだけで以下の画面をブラウザで開くことができます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/ae922a5f-3f0a-1e46-e4b7-47ecc0e8e173.png)


https://laravel.com/docs/10.x/sail

## 環境構築
プロジェクトを作成したいディレクトリに移動して、任意のアプリケーションの名前を決め、以下コマンドを叩いてください

```zsh:zsh
curl -s https://laravel.build/{アプリケーションの名前} | zsh
```

パスワード入力が求められ、入力し以下の画面になればOKです
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/58358311-db55-1822-067c-f9bb83c58671.png)



次にDocker Desktopを起動しておき、sailを起動します

```zsh:zsh
cd {アプリケーションの名前} && ./vendor/bin/sail up
```

初回の立ち上げは結構時間かかります

Docker DesktopでStatusが全部Runnigになってればオッケーです！

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/bb282830-c75a-0033-e692-d344fd917199.png)


ブラウザでlocalhostにアクセスすると、Laravelのウェルカム画面が表示されます

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/ae922a5f-3f0a-1e46-e4b7-47ecc0e8e173.png)


毎回、sailを起動するのに`./vendor/bin/sail up`と入力するのは手間なので、エイリアスを登録しておきます

```zsh:zsh
echo "alias sail='[ -f sail ] && bash sail || bash vendor/bin/sail'" >> ~/.zshrc
```

これで以降は、`sail up`で立ち上がります
止める時は、`sail stop`かDocker Desktopの停止ボタンのどちらかで停止してください



# Breeze
## Breezeとは？
Laravel Breezeは、Laravelの認証機能を簡単に追加するためのライブラリです
Breezeを使用することで、ログイン・登録機能を簡単に実装することができます
以下の画面の右上に
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/ae922a5f-3f0a-1e46-e4b7-47ecc0e8e173.png)
ログインと登録をつけてくれます
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/307a81ef-7d46-01e6-22b5-ac63abd258a4.png)


## Breezeのインストール
まずは、以下コマンドでコンテナの中に入りましょう

```zsh:zsh
sail shell
```
もしくは
```bash:bash
docker exec -it {アプリケーションの名前} bash
```
で中に入れます
ちなみに、ここでbashなのは、コンテナ内がデフォルトでbashだからです
気になる人はコンテナの中で`echo $SHELL`してみてください
**今後、記述コードがbashとなっているものはコンテナ内でコマンドを実行してください**

以下コマンドで、Breezeをインストールしてください。`composer.json`ファイルにBreezeがインストールされているかも確認してください。
```bash:bash
composer require laravel/breeze
```

次に、ログイン画面のBladeファイルを持ってきたいので、以下コマンドを入力してください

```bash:bash
php artisan breeze:install
```

実行すると対話形式で3つ聞かれるので、答えてください
Bladeスタックと、ダークモード対応、テストは特にしないので`no`を選択

```bash:bash
Which stack would you like to install?
  blade ............................................... 0
  react ............................................... 1
  vue ................................................. 2
  api ................................................. 3
❯ 0

  Would you like to install dark mode support? (yes/no) [no]
❯ yes

  Would you prefer Pest tests instead of PHPUnit? (yes/no) [no]
❯ no
```

これにより、ログイン・登録画面などが自動的に生成されます
`localhost`にアクセスすると、作成されていることが確認できます
![スクリーンショット 2023-05-25 14.40.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/8db588e5-7d5c-9b99-a260-f55c53470ada.png)

## DBの準備
一旦、アカウント登録するためDBの準備をします
まず、migrationを実行します
```bash:bash
php artisan migrate
```
次に、envを参照しDBクライアントに接続したら、`localhost`で右上の`Register`で入力し、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/9a2a4987-ae55-611f-9297-69d66ce7ca3f.png)

こちらの画面に遷移できれば、Breezeのインストールは完了です

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/56d3acd1-d398-9660-cde8-11f6bc0d97b9.png)

DBの中身も一応確認すると、入ってますね

![スクリーンショット 2023-05-25 14.53.04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/f2fa824f-58d3-f2c6-672a-7ddc471882ac.png)

# Googleログイン
ここからが今回のメインです
先ほどまでで作った、ログイン画面にGoogleログインを実装していきます

## Socialiteのインストール
Laravel Socialiteは、Laravelフレームワークでソーシャルメディア認証（Social Authentication）を簡単に実装するためのオフィシャルなパッケージです


https://laravel.com/docs/10.x/socialite

コンテナ内で、以下コマンドでSocialteをインストールしてください

```bash:bash
composer require laravel/socialite
```

次に、`config/app.php`ファイル


## GCコンソールで認証情報登録
以下URLからGoogle Cloudのコンソール画面にいき認証情報の登録を行います


https://console.cloud.google.com

新たにプロジェクトを作成し、`APIとサービス`→`認証情報`をクリックし、`認証情報を作成`をクリック
※初めての場合、`OAuth 同意画面`でアプリケーション名だけ入力して同意してください
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/3b13031f-66cc-16ff-8503-25e0b3c1a0b6.png)

`OAuth クライアント ID の作成`をクリック
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/b5a8ecd0-92de-43ca-8a1c-5773eb7aa7e3.png)

`アプリケーションの種類`を`ウェブアプリケーション`を選択し、
`承認済みの JavaScript 生成元`→`http://localhost`
`承認済みのリダイレクト URI`→`http://localhost/auth/google/callback`
と入力し、作成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/e10cf7fc-47e6-edc8-f07b-16ba7c1657c6.png)

作成後に出るモーダルから`クライアントID`と`クライアントシークレット`を控えておく(マスクがうまくできるか心配で切り抜きました、、)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/a8faeaa6-7f11-469e-f5af-9d594bbd791c.png)
↓この右側にあるものを控える
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/d7afe795-8f31-511b-876c-e79514a0bac7.png)

## Laravel側で設定

控えたものを、`.env`ファイルの一番下に以下の形で記述

```text:.env
GOOGLE_KEY="******************************"
GOOGLE_SECRET="******************************"
GOOGLE_REDIRECT_URI="http://localhost/auth/google/callback"
```

次に、`service/config.app`にGoogleとの連携のための設定を記述します
```php:config.php
    'google' => [
        'client_id' => env('GOOGLE_KEY'), 
        'client_secret' => env('GOOGLE_SECRET'), 
        'redirect' => env('GOOGLE_REDIRECT_URI'), 
      ],
```

### コントローラー
Googleアカウントを使用してログイン機能を実装するためのコントローラを作成します

```bash:bash
php artisan make:controller GoogleLoginController
```

`GoogleLoginController.php`ファイルの中身は以下のように書き換えます
```php:GoogleLoginController.php
<?php

namespace App\Http\Controllers;

use Laravel\Socialite\Facades\Socialite;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Exception;
use Illuminate\Support\Facades\Log;

class GoogleLoginController extends Controller
{
    public function redirectToGoogle()
    {
        return Socialite::driver('google')->redirect();
    }

    public function handleGoogleCallback()
    {
        try {
            $socialiteUser = Socialite::driver('google')->user();
            $email = $socialiteUser->email;

            $user = User::firstOrCreate(['email' => $email], [
                'name' => $socialiteUser->name,
            ]);

            Auth::login($user);

            return redirect()->intended('dashboard');
        } catch (Exception $e) {
            Log::error($e);
            throw $e;
        }
    }
}

```



### ルーティング
`web.php`に`GoogleLoginController`を追加し、認証用のルートを定義します

```php:web.php
use App\Http\Controllers\GoogleLoginController;

Route::get('/auth/google', [GoogleLoginController::class, 'redirectToGoogle'])
    ->name('login.google');

Route::get('/auth/google/callback', [GoogleLoginController::class, 'handleGoogleCallback'])
    ->name('login.google.callback');

```


### ビュー
ログイン画面のBladeファイルを以下のように変更します

```php:login.blade.php
<x-guest-layout>
    <!-- Session Status -->
    <x-auth-session-status class="mb-4" :status="session('status')" />

    <form method="POST" action="{{ route('login') }}">
        @csrf

        <!-- Email Address -->
        <div>
            <x-input-label for="email" :value="__('Email')" />
            <x-text-input id="email" class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autofocus autocomplete="username" />
            <x-input-error :messages="$errors->get('email')" class="mt-2" />
        </div>

        <!-- Password -->
        <div class="mt-4">
            <x-input-label for="password" :value="__('Password')" />

            <x-text-input id="password" class="block mt-1 w-full"
                            type="password"
                            name="password"
                            required autocomplete="current-password" />

            <x-input-error :messages="$errors->get('password')" class="mt-2" />
        </div>

        <!-- Remember Me -->
        <div class="block mt-4">
            <label for="remember_me" class="inline-flex items-center">
                <input id="remember_me" type="checkbox" class="rounded dark:bg-gray-900 border-gray-300 dark:border-gray-700 text-indigo-600 shadow-sm focus:ring-indigo-500 dark:focus:ring-indigo-600 dark:focus:ring-offset-gray-800" name="remember">
                <span class="ml-2 text-sm text-gray-600 dark:text-gray-400">{{ __('Remember me') }}</span>
            </label>
        </div>

        <div class="flex items-center justify-between mt-4">
            <div>
                @if (Route::has('password.request'))
                    <a class="underline text-sm text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-100 rounded-md focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500 dark:focus:ring-offset-gray-800" href="{{ route('password.request') }}">
                        {{ __('Forgot your password?') }}
                    </a>
                @endif
            </div>

            <div>
                <x-primary-button>
                    {{ __('Log in') }}
                </x-primary-button>
            </div>
        </div>
    </form>

    <div class="flex items-center justify-end mt-4">
        <a href="{{ route('login.google') }}" class="ml-3 inline-flex items-center">
            <img src="https://developers.google.com/identity/images/btn_google_signin_dark_normal_web.png" style="margin-left: 3em;">
        </a>
    </div>
</x-guest-layout>

```

### マイグレーション
Googleログイン時はパスワードは使用しないので、パスワードをNULL許容するように`password`カラムを変更いたします
以下コマンドでマイグレーションファイルを生成します

```bash:bash
php artisan make:migration modify_password_column_nullable_in_users_table --table=users
```

生成されたマイグレーションファイルの中身を以下のように書き換えます

```php:mi
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class ModifyPasswordColumnNullableInUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('password')->nullable()->change();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('password')->nullable(false)->change();
        });
    }
}

```

マイグレートします

```bash:bash
php artisan migrate
```

# ログイン確認
ログイン画面にGoogleログインが出ており、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/8035fe24-0c21-410e-b3d7-fcdf73d54114.png)
ログインし、
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/7e46cde1-46f6-29fe-cfc3-d055b2ef06a9.png)
この画面に辿り着ければ完了です！お疲れ様でした！
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2779963/49afe3cd-e6a4-dc83-b4f1-e3f78c56e70a.png)


# おわり
見ていただきありがとうございます！
Laravel Sailやソーシャルログインの実装が意外と簡単にできてびっくりしました。
OAuthが雰囲気でしかわかっていないのでこれからちゃんと学ぼうと思います。

# 参考
以下参考にさせていただいた記事です。ありがとうございました。

構成をお願いして真似させていただきました

https://qiita.com/Michinosuke/items/09c30fde4ca7168f96ef

Sailはこちらも端的でわかりやすいです

https://qiita.com/haru-nk/items/8772da65d64698b91e65

流れを確認するのに参考にさせていただきました

https://qiita.com/u-dai/items/91df3b923dc82fed5b76