Laravel8でGoogleのソーシャルログインを実装してみた

#ソーシャルログインとは
ソーシャルログイン（ソーシャルサインイン）とは、ユーザーが使い慣れた既存のSNSアカウントを利用して、Webサイトやサービスにログインできる機能です。ちなみに日本で最も利用されているソーシャルログインは、Line ログインだそうです。![05E61DAC-45BA-4846-8926-FC3DC14C3ECC_1_201_a.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299864/035d1763-357e-5b3a-f1f8-5b353f144ecf.jpeg)
参考: [2020最新調査レポート](https://socialplus.jp/report/2020)

#運営側のメリット
* リピート率の向上 : ログインのしやすさから、ユーザー離れを防ぐ
* セキュリティの強化

#今回の概要
![48FD8147-D476-40D2-BCB8-0142F654EAF3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299864/90bf3bc3-2414-f9ea-c5db-e4c4ee33a4e6.png)

#読んでほしい人
* laravel8にsnsログインを実装したい方
* サイトに来てくれた方のログインの手間を減らす工夫をしたい方

#イメージ
* Google Api を使うので難しそう
* これから使えそう

#軽く自己紹介
プログラミングスクールにて、現在web系の言語を中心に勉強中です。ちなみに現時点で、プログラミング歴２ヶ月目の新人です。(2021/05/01)解釈等間違っていた場合は、ぜひコメントお願いします。

#Start地点
* laravel のバージョン8をインストールしている
* jetstream をインストールしている
* composer をインストールしている
* local で行う際は、localhostと呼び出すとgoogle 認証をしたいアプリが出てくるようにしておく。
今回は、google 認証を行いたいアプリがgoogle なので以下のように.htaccess を変更した![スクリーンショット 2021-05-04 18.23.28.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299864/fc8fb345-7e0f-9e1a-73d1-287c25641231.png)

#Step1 : Socialite をインストールする
Google Account の API connect を行う際、Socialite package が必要になります。そのため、mac の場合はターミナルで、windows の場合はコマンドプロンプトでインストールしていきます。(**注意** 筆者は、mac を使っているため、windows では、正常には動かない場合があります。)

``` 
composer require laravel/socialite
```
#step2 :Google App を作成する
Google 認証機能には、Google Developers Console のクライアント id とシークレットのパスが必要になります。そのために Google アカウントで入り、新規プロジェクトを作成していきます。 ![FABF73C2-8317-41FB-BB33-9F4A447BFB73_1_201_a.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299864/bd0c0dfd-8d85-0727-76cb-71d288e03019.jpeg)

![0896DA70-1765-471F-9D5C-992506CBEB56.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299864/77b7f957-8c67-da5e-fcea-ca6b20ad768a.jpeg)

![69549CC1-E1BC-4D81-8259-0E05FCD7FE1E.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299864/fa668642-acdd-ffca-7222-804e377993a8.jpeg)

![40E4B844-A84D-4AD5-93C2-64CD439C9E56.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299864/efd96965-2dd7-a689-8652-968060be7dd0.jpeg)

![B12EA6B2-CFAB-4516-AB81-0EE30C2DA1CC.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299864/ac8bcb53-7c0e-b6b4-749c-ed67721a4ac0.jpeg)

![9EA15A3D-8161-4097-BA44-8FBA566BA837_1_201_a.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299864/442d6cb2-6925-5ca9-c515-c5eb24fa454b.jpeg)

クライアントIDとクライアントシークレットを作成後、後々のためにコピーしておきます。承認済みのリダイレクト URIは、

```
http://localhost/login/google/callback
```
を加えておきます。
laravel の config/services.php にペーストします。

```
return [
    ....
    'google' => [
        'client_id' => 'app id',
        'client_secret' => 'add secret',
        'redirect' => 'http://localhost/login/google/callback',
    ],
]
```
#Step3: Google id をデータベースに追加していきます。
ターミナルに以下のコマンドを打ち、user テーブルを作成します。

``` 
php artisan make:migration add_google_id_column
```
そして、以下のファイルに、変更します。

```php:migrations
<?php

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

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

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }
}
```

```app/Models/User.php
<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasApiTokens;
    use HasFactory;
    use HasProfilePhoto;
    use Notifiable;
    use TwoFactorAuthenticatable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'google_id'
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password',
        'remember_token',
        'two_factor_recovery_codes',
        'two_factor_secret',
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    /**
     * The accessors to append to the model's array form.
     *
     * @var array
     */
    protected $appends = [
        'profile_photo_url',
    ];
}
```
#Step4: Google Login の際の、パスを作る
Google 認証のテーブルを作成したので、次にパスを設定していきます。
以下のファイルを変更してください。

```routes/web.php
<?php

use Illuminate\Support\Facades\Route;

use App\Http\Controllers\GoogleController;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/

Route::get('/', function () {
    return view('welcome');
});

Route::middleware(['auth:sanctum', 'verified'])->get('/dashboard', function () {
    return view('dashboard');
})->name('dashboard');

Route::get('/login/google', [GoogleController::class, 'redirectToGoogle']);
Route::get('/login/google/callback', [GoogleController::class, 'handleGoogleCallback']);
```
#Step5:コントローラーを制作する
Google call back の処理を行う際の、Google 認証のメソッドを追加していきます。
以下のコードをGoogleController.phpとして配置します。


```app/Http/Controllers/GoogleController.php
<?php

namespace App\Http\Controllers;

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

class GoogleController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function redirectToGoogle()
    {
        return Socialite::driver('google')->redirect();
    }
        
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function handleGoogleCallback()
    {
        try {

            $user = Socialite::driver('google')->user();

            $finduser = User::where('google_id', $user->id)->first();

            if($finduser){

                Auth::login($finduser);

                return redirect()->intended('dashboard');

            }else{
                $newUser = User::create([
                    'name' => $user->name,
                    'email' => $user->email,
                    'google_id'=> $user->id,
                    'password' => encrypt('123456dummy')
                ]);

                Auth::login($newUser);

                return redirect()->intended('dashboard');
            }

        } catch (Exception $e) {
            dd($e->getMessage());
        }
    }
}
```
#Step6: View を変更する
最後に、login.blade.php ファイルを変更して完成です。

```public/views/auth/login.blade.php
<x-guest-layout>
    <x-jet-authentication-card>
        <x-slot name="logo">
            <x-jet-authentication-card-logo />
        </x-slot>

        <x-jet-validation-errors class="mb-4" />

        @if (session('status'))
            <div class="mb-4 font-medium text-sm text-green-600">
                {{ session('status') }}
            </div>
        @endif

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

            <div>
                <x-jet-label value="Email" />
                <x-jet-input class="block mt-1 w-full" type="email" name="email" :value="old('email')" required autofocus />
            </div>

            <div class="mt-4">
                <x-jet-label value="Password" />
                <x-jet-input class="block mt-1 w-full" type="password" name="password" required autocomplete="current-password" />
            </div>

            <div class="block mt-4">
                <label class="flex items-center">
                    <input type="checkbox" class="form-checkbox" name="remember">
                    <span class="ml-2 text-sm text-gray-600">{{ __('Remember me') }}</span>
                </label>
            </div>

            <div class="flex items-center justify-end mt-4">
                @if (Route::has('password.request'))
                    <a class="underline text-sm text-gray-600 hover:text-gray-900" href="{{ route('password.request') }}">
                        {{ __('Forgot your password?') }}
                    </a>
                @endif

                <x-jet-button class="ml-4">
                    {{ __('Login') }}
                </x-jet-button>
            </div>
            <div class="flex items-center justify-end mt-4">
                <a href="{{ url('login/google') }}">
                    <img src="https://developers.google.com/identity/images/btn_google_signin_dark_normal_web.png" style="margin-left: 3em;">
                </a>
            </div>
        </form>
    </x-jet-authentication-card>
</x-guest-layout>
```
#今回の完成図
![8644420F-4C54-4684-9898-E5CE530117C0.jpeg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299864/785d5c10-19c9-aeec-3625-0609e17ed56c.jpeg)
![Untitled Diagram (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1299864/6ee5230f-aacd-9677-af92-225ee6e5fb6f.png)

#最後に
作る前は、難しそうに見えました。しかし実際にやってみると、基本コピペでできます。
次は、「reCAPTCHA」でのログイン画面を作ってみたいと思います。最後まで見ていただきありがとうございました。よければフォローお願いします。
#参考文献
ソーシャルログインの解説
https://qiita.com/TakahikoKawasaki/items/e37caf50776e00e733be
ソーシャルログインの表
https://blog.feedmatic.net/about-social-login/
Google Api のまとめ
https://morioh.com/p/0befb987d99a