Laravel5.8プロジェクトにGoogleログイン機能をつける

# 概要

DockerやPHPの勉強にと作成したLaravelプロジェクトにGoogleログイン機能をつけてみました。

## 手順
1. GCPの設定
2. Laravel側の設定

## GCPの設定

### GoogleCloudPlatform(GCP)の登録
Google認証を実装するには、まずGoogleCloudPlatform(GCP)の登録が必要です。
Googleアカウントがあれば簡単に出来ます。

GCP:
https://console.cloud.google.com/getting-started?hl=ja

### プロジェクトの作成
GCPのホームから作成ができます。
2019.07現在では、「Google Cloud Platform」というロゴマークの右横にプロジェクト名が表示されてます。選択するとモーダルが開き「新しいプロジェクト」作成の導線が現れます。

<img width="601" alt="screenshot 2019-07-03 8.26.31.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/05c73319-2dce-56a0-9748-1dc6ee22006e.png">

「プロジェクト名」には、とりあえずLaravelプロジェクトと同一の名前を、
今回は個人のテスト用なので「場所」はそのまま「組織なし」を選択し作成します。

### 認証情報の設定

作成したプロジェクトから「APIとサービス＞認証情報＞OAuth同意画面」に移動します。
ここにもLaravelプロジェクトと同一の名前を入れました。
＊Google認証をするときに一番上に出てくる「●●●●●」に移動の●部分に入ります。

作成をクリックすると、APIとサービスのページに戻りモーダルが開くので
そこで「認証情報を作成＞OAuthクライアントID」を選択します。

<img width="960" alt="screenshot 2019-07-03 8.57.03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/f837dd19-050a-0333-2b5b-e54cb78a5943.png">

下記の画面が表示されるので
「ウェブアプリケーション」にチェック、「名前」、「承認済みのリダイレクトURI」を埋めて作成します。

「名前」は任意で、
「承認済みのリダイレクトURI」はLaravel側で使うのでそれを考慮に入れてください。
とりあえず今回は"http://localhost/auth/callback/google/" にしました。

(重要)
作成したあと、「クライアントID」と「クライアントシークレット」が表示されます。後ほど使用するのでメモっておいてください。

<img width="859" alt="screenshot 2019-07-03 8.58.30.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/09768c33-d688-3a57-44ea-96245af046c2.png">

これでGCPの設定は終わりです。

## Laravel側の設定

Laravelでの実装ですが、
今回は簡易的に行うため、Laravelのデフォルトで作られるusersテーブルをそのまま使います。

```
このあと必要になるパッケージを先にインストール
$ composer require laravel/socialite

laravelデフォルトで用意されている認証機能作成のコマンド
$ php artisan make:auth

テーブル作成
$ php artisan migrate

Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table

さらに後ほど必要になるコントローラを作っておきます
$ php artisan make:controller OAuthLoginController

(dbコンテナにてテーブルが作られていることを確認しておく)
mysql> show tables;
+--------------------------+
| Tables_in_laravel-cloud9 |
+--------------------------+
| migrations               |
| password_resets          |
| users                    |
+--------------------------+
3 rows in set (0.00 sec)
```

必要な設定を追加していきます

```src/.env
先ほどGCPの設定の時に作成したものを使用します
GOOGLE_CLIENT_ID=クライアントID
GOOGLE_CLIENT_SECRET=クライアントシークレット
GOOGLE_CALLBACK_URL=リダイレクトURL
```

```src/config/app.php
// サービスプロバイダの登録
'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        /* 省略 */
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,

        Laravel\Socialite\SocialiteServiceProvider::class,//(追加)
    ],

/* 省略 */
 'aliases' => [

        'App' => Illuminate\Support\Facades\App::class,
        'Arr' => Illuminate\Support\Arr::class,
        /* 省略 */
        'Validator' => Illuminate\Support\Facades\Validator::class,
        'View' => Illuminate\Support\Facades\View::class,
        
        'Socialite' => Laravel\Socialite\Facades\Socialite::class,//(追加)
    ],

```

```src/config/services.php
return [
    
    /*
    |--------------------------------------------------------------------------
    | Third Party Services
    |--------------------------------------------------------------------------
    |
    | This file is for storing the credentials for third party services such
    | as Stripe, Mailgun, SparkPost and others. This file provides a sane
    | default location for this type of information, allowing packages
    | to have a conventional place to find your various credentials.
    |
    */

    /* 省略 */

    'stripe' => [
        'model' => App\User::class,
        'key' => env('STRIPE_KEY'),
        'secret' => env('STRIPE_SECRET'),
        'webhook' => [
            'secret' => env('STRIPE_WEBHOOK_SECRET'),
            'tolerance' => env('STRIPE_WEBHOOK_TOLERANCE', 300),
        ],
    ],

    /* 追加ここから */
    'google' => [
        'client_id' => env('GOOGLE_CLIENT_ID'),
        'client_secret' => env('GOOGLE_CLIENT_SECRET'),
        'redirect' => env('GOOGLE_CALLBACK_URL'),
    ],
    /* 追加ここまで */
];
```

```src/routes/web.php
/* 省略 */
Route::get('/home', 'HomeController@index')->name('home');
/* 省略 */
// Controllerメソッドへのルート定義
Route::get('/auth/{service}', 'OAuthLoginController@getGoogleAuth')->where('service', 'google');
Route::get('/auth/callback/google', 'OAuthLoginController@authGoogleCallback');

```

```src/app/Http/Controllers/OAuthLoginController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\User;
use Socialite;
use Auth;

class OAuthLoginController extends Controller
{
    // Googleの認証ページへのリダイレクト処理
    public function getGoogleAuth($provider)
    {
        return Socialite::driver($provider)->redirect();
    }

    // Googleの認証情報からユーザー情報の取得
    public function authGoogleCallback()
    {
        $googleUser = Socialite::driver('google')->user();
        $user = User::firstOrNew(['email' => $googleUser->email]);
        
        if (!$user->exists) {
            $user['name'] = $googleUser->getNickName() ?? $googleUser->getName() ?? $googleUser->getNick();
            $user['email'] = $googleUser->email; // Gmailアドレス
            $user['password'] = str_random(); // 適当に生成

            $user->save();
        }
        
        Auth::login($user);
        return redirect()->route('home');
    }
}
```

最後に、ログイン画面にGoogleログイン用のボタンを用意します。

```src/resources/views/auth/login.blade.php
// ログイン画面にGoogleログインボタンを配置
<form method="POST" action="{{ route('login') }}">
/* 省略 */
</form>
<a href="auth/google">Googleログイン</a> // 追加
```

この状態で「localhost:8080/login」にアクセスすると、
アンカーリンクを表示しているだけなので位置はおかしいですが、
「Googleログイン」ボタンを押すとGoogleのログイン画面にリダイレクトします。

<img width="1209" alt="screenshot 2019-07-04 19.55.46.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/c621a1e2-8391-4cdd-853a-598d6ed9bc7e.png">

<img width="1233" alt="screenshot 2019-07-04 20.00.20.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/46053/f160cc79-f401-c994-1371-3f9863199c1d.png">

＊「Word Container」の部分が、GCPで認証情報の設定をした際に入力した名前です。

あとはログインしたいユーザーでログインすれば、
DBにGoogleアカウントの情報が入ります。

```
mysql> select * from users;
+----+--------------+--------------------+-------------------+------------------+----------------+---------------------+---------------------+
| id | name         | email              | email_verified_at | password         | remember_token | created_at          | updated_at          |
+----+--------------+--------------------+-------------------+------------------+----------------+---------------------+---------------------+
|  1 | ○○○○○     | xxxxxxx@gmail.com | NULL              | ZabdYEZPWOKeIpbp | NULL           | 2019-07-02 23:15:15 | 2019-07-02 23:15:15 |
+----+--------------+--------------------+-------------------+------------------+----------------+---------------------+---------------------+
```

## 最後に

今回はGoogleログインでしたが、
SocialiteではFacebook、Twitterはじめ他にもサポートしているサービスがいくつかあるようです。
他のサービスでのログインも併用したい場合にはusersテーブルの構成を少し変える必要がありそうです。
(ex. GoogleとFacebookで同じメールアドレスを登録している可能性があるので)

>典型的なフォームベースの認証に付け加え、LaravelはLaravel Socialite(=名士)による、OAuthプロバイダによるシンプルで便利な認証方法も提供しています。Socialiteは現在、Facebook、Twitter、LinkedIn、Google、GitHub、GitLab、Bitbucketによる認証をサポートしています。

https://readouble.com/laravel/5.8/ja/socialite.html

### 参考
https://tech.bita.jp/article/28