【Laravel】 Laravel SocialiteでSNS認証を実装する 


Laravel初学者がSocialiteでSNS認証を実装しようとして、苦戦したので備忘録としての投稿です。

Google、Facebook、TwitterのほかにLINEでもログインできるようにしています。

今回はxamppを使用して実装していきます。

完全に仕組みを理解できない部分もあるので、冗長な記述が多いとは思いますが、
私が実装できた方法のメモ書きみたいな物なので、ご容赦ください。

#開発環境
・Windows10 64bit
・Laravel Framework 7.29.3
・XAMPP 7.4.11
・PHP 7.4.11
・Apache 2.4.46
・MariaDB 10.4.14

#実装手順

Laravelやxampp等の環境構築は出来ているものとして説明していきます。

xamppのSSL化もしてあります。なのでURLの最初が`https://`から始まっています。
SSL化が必要ない方はローカルURLの`https://`を`http://`で読み替えてください。

SSL化については以下の記事を参考にさせていただきました。

XAMPP for WindowsでSSLを有効にする
https://qiita.com/sutara79/items/21a068494bc3a08a4803

##1.Laravelプロジェクトを作成

 C:\xampp\htdocsに移動してプロジェクトを作成します。

今回はLaravel7を使いたいので、バージョン指定をしています。

バージョン指定は
`composer create-project "laravel/laravel=バージョン" プロジェクト名`で行います。


```
$ composer create-project "laravel/laravel=7.*" social-login
```

プロジェクト作成後、`cd social-login`でディレクトリ移動

##2.Socialiteをインストールする

```
$ composer require laravel/socialite 
```

##3.ログイン機能を実装する
まずはlaravel/uiライブラリをインストールします。
laravel7ではuiのバージョンを指定しないとエラーが出るのでバージョン2.4を指定しています。

```
$ composer require laravel/ui:^2.4
```

インストール後、↓のコマンドで認証機能をログイン機能を実装します

```
$ php artisan ui vue --auth
```

![laravel.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/904420/05e9e9ab-fe3c-19f3-561d-42ac9d86e290.jpeg)

Apacheを起動させてhttps://localhost/social-login/public/ にアクセスすると上の画面が表示されます。

xamppを使ってない人は

```
$ php artisan serve
```

でビルトインサーバ起動させて、http://localhost:8000/ にアクセスすればOKです。


右上にLOGINが追加されて、ログイン機能が実装されます。

##4.ログイン画面のレイアウトを整える
フロントエンドに必要なパッケージをインストールしていきます。

###node.jsのインストール
node.jsをまだインストールしてない人は、[Node.jsのホームページ](https://nodejs.org/ja/)から
推奨版をインストールしてPCを再起動してください。

```
$ node --version 
```
上のコマンドでnode.jsのバージョン出れば、インストールできています。


###パッケージのインストール


```
$ npm install
```

↑パッケージをインストールして

```
$ npm run dev
```

↑ビルドします

![login.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/904420/ce3e5081-5482-e681-a358-632eef8ba72c.jpeg)
これでログイン画面のレイアウトが整います。

##5.データベースの準備

xamppを使っている人はDBから作成します。使ってない人は飛ばしてください。

###xammpを使っている人が必要な準備

![xampp.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/904420/3adc94ff-efba-9030-8d93-f3b36c1b4d2a.jpeg)
Apacheをスタートさせた後、mySQLをスタートさせて、右横のAdminをクリック。

![Untitled Project (1).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/904420/7e508fca-0cd9-6bed-208c-4174788976d3.jpeg)
左上の新規作成をクリック

![Untitled Project (2).jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/904420/bc711453-7b2a-67b5-5a10-6ae0e3510e49.jpeg)
データベース名にsocial_loginと入力して作成をクリック

これでDBが作成されます。

次に、今作ったDBをアプリで使用できるようにします。

``C:\xampp\htdocs\social-login\.env``

```&#x20;.env
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=social_login  //ここを書き換える
DB_USERNAME=root
DB_PASSWORD=
```
`DB_DATABASE=laravel`となっているところを上記に書き換えます。

これで、作成したDBが使えるようになります。


##7.Userテーブルを作成する

プロジェクトを作成したときに自動でマイグレーションファイルが出来るので、そのままマイグレートを実行します。

```
$ php artisan migrate
```

これでUsersテーブルが作成されます。

###マイグレーションファイルの作成

SNSログインではユーザーのパスワードを必要としないので、Usersテーブルのpasswordカラムをnull(からっぽ)でも許容できるようにしなければなりません。

また、SNSからユーザーの名前とメールアドレスの情報を取得できるのですが、
今回はそれらの情報をDBに保存しないようにしたいので、emailカラムもnullを許容できるようにします。
(個人情報を取り扱いたくないのと、LINEなどはemailを取得する際に必要な手順があるため)
<br>

では、Usersテーブルの変更を行うマイグレーションファイルを作成していきます。

```
$ php artisan make:migration [マイグレーションファイル名] --table=[テーブル名]
```
のコマンドでマイグレーションファイルが作成できます。

```
$ php artisan make:migration change_users_table --table=users
```

上記コマンドを実行すると`C:\xampp\htdocs\social-login\database\migrations`のなかに新しいマイグレーションファイルが作成されるので、変更内容をそこに記述します。

```
<?php

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

class ChangeUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->enum('provider', ['google', 'facebook', 'twitter', 'line'])->nullable();  //カラム追加
            $table->string('provided_user_id')->nullable();
            $table->string('email')->nullable()->change(); //nullを許容
            $table->string('password')->nullable()->change();

            $table->unique(['provider', 'provided_user_id']); //ユニーク制約
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropUnique(['provider', 'provided_user_id']); //ユニーク制約を解除

            $table->dropColumn('provider');  //カラムの削除
            $table->dropColumn('provided_user_id');
            $table->string('email')->nullable(false)->change(); //nullを許容しない
            $table->string('password')->nullable(false)->change();

            
        });
    }
}

```
<br>
テーブルを変更する場合には、doctrine/dbalをインストールする必要があります。
入れてない方は下のコマンドをでインストールしてください。

```
$ composer require doctrine/dbal:2.9.3
```
現在の最新バージョンの2.10だとうまくいかなかったので今回はバージョン指定しています。
問題なそうな方は末尾の`:2.9.3`の記述を外してください。


```
$ php artisan migrate
```
上のコマンドでマイグレーションを実行してください。
<br>
そうするとUsersテーブルがこのようになります。
![screenshot (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/904420/0688ffa5-d42e-b7db-f745-cf0d330a7f22.png)


##8.Usersモデルに記述をする
`C:\xampp\htdocs\social-login\app\User.php`を以下の記述をします。

```
<?php

namespace App;

use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;
use Illuminate\Auth\Authenticatable;

class User extends Model implements AuthenticatableContract
{
    use Authenticatable, Notifiable;

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

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

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

    public function getAuthPassword()
    {
        return $this->password;
    }

    /**
     * Get the column name for the "remember me" token.
     *
     * @return string
     */
    public function getRememberTokenName()
    {
        return '';
    }
}
```

##9.コントローラーに記述をする
`C:\xampp\htdocs\social-login\app\Http\Controllers\Auth\LoginController.php`に以下の記述をします。


```
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Providers\RouteServiceProvider;
use Illuminate\Foundation\Auth\AuthenticatesUsers;

use Socialite;
use App\User;
use Illuminate\Support\Facades\Auth;


class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = RouteServiceProvider::HOME;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

      /**
     * OAuth認証先にリダイレクト
     *
     * @param str $provider
     * @return \Illuminate\Http\Response
     */
    public function redirectToProvider($provider)
    {
        return Socialite::driver($provider)->redirect();
    }


    /**
    * OAuth認証の結果受け取り
    *
    * @param str $provider
    * @return \Illuminate\Http\Response
    */
    public function handleProviderCallback($provider)
    {
        $provided_user = Socialite::driver($provider)->user();

        $user = User::where('provider', $provider)
            ->where('provided_user_id', $provided_user->id)
            ->first();

        if ($user === null) {
            // redirect confirm
            $user = User::create([
               'name'               => $provided_user->name,
               'provider'           => $provider,
               'provided_user_id'   => $provided_user->id,
            ]);
        }

        Auth::login($user);

        return redirect($this->redirectTo);
    }

}
```

##10.ルーティングを記述する
`C:\xampp\htdocs\social-login\routes\web.php`の一番下に以下の記述を追加します。

```
Route::get('/login/{provider}', 'Auth\LoginController@redirectToProvider');
Route::get('/login/{provider}/callback', 'Auth\LoginController@handleProviderCallback');
```

これでSNSログイン機能の記述はOKです。


##11.socialiteの拡張
LINEなどのsocialiteが元から対応しているプロバイダ以外を追加する場合は以下の記述が必要です。
（Google、Facebook、Twitter、Linkedin、GitHub、GitLab、Bitbucketが元から対応しているはずなので、これらだけのSNS認証ならここの記述は不要です。）

###追加するsoccialiteドライバのインストールする

以下のコマンドで追加するsocialiteのドライバをインストールします


LINE用

```
$ composer require socialiteproviders/line
```

上記以外のドライバをインストールしたい場合はhttps://socialiteproviders.com/about/ にアクセスして対応したプロバイダのコマンドを探してください。

次に`C:\xampp\htdocs\social-login\config\app.php`の'providers' =>の中に以下の記述を追加します。

```
'providers' => [

    /*
    * 追加のプロバイダ
    */

    SocialiteProviders\Manager\ServiceProvider::class, // この一行を追加
];
```

次に`C:\xampp\htdocs\social-login\app\Providers\EventServiceProvider.php`に記述を追加します。

```
protected $listen = [

    \SocialiteProviders\Manager\SocialiteWasCalled::class => [
        'SocialiteProviders\\Line\\LineExtendSocialite@handle',  //LINE
    ],
];
```

今回はLINEの記述だけをしていますが、ほかのプロバイダを追加したい場合にもhttps://socialiteproviders.com/about/ にアクセスして、追加したいプロバイダのページに飛んで`Add provider event listener`のところにあるコードをコピペしてください。

##12.クライアントIDとシークレットキーを取得する

今回はクライアントIDとシークレットキーの取得方法は割愛します。
以下のサイトからAPIキーを取得してください。

・Google
　https://console.developers.google.com/ 
・Facebook
　https://developers.facebook.com
・Twitter
　https://apps.twitter.com 
・LINE
　https://developers.line.biz/ja/services/line-login/


##13.取得したクライアントIDを記述する
`C:\xampp\htdocs\social-login\config\services.php`のreturnの中に追加したプロバイダを追記します。

```
return [
    'facebook' => [    
        'client_id' => env('FACEBOOK_CLIENT_ID'),  
        'client_secret' => env('FACEBOOK_CLIENT_SECRET'),  
        'redirect' => env('FACEBOOK_REDIRECT_URI'),
      ],

    'google' => [
        'client_id' => env('GOOGLE_CLIENT_ID'),
        'client_secret' => env('GOOGLE_CLIENT_SECRET'),
        'redirect' => env('GOOGLE_REDIRECT_URL'),
    ],

    'twitter' => [    
        'client_id' => env('TWITTER_CLIENT_ID'),  
        'client_secret' => env('TWITTER_CLIENT_SECRET'),  
        'redirect' => env('TWITTER_REDIRECT_URI') 
      ],

    'line' => [
        'client_id'     => env('LINE_CLIENT_ID'),
        'client_secret' => env('LINE_CLIENT_SECRET'),
        'redirect'      => env('LINE_REDIRECT_URL'),
    ],

];
```

次に`C:\xampp\htdocs\social-login\.env`の一番下に取得したクライアントIDとシークレットキーを追記します。
リダイレクト先のURLも同時に入力していきます。

「取得したクライアントID」と「取得したシークレットキー」のところはそれぞれ書き換えてください。

```
FACEBOOK_CLIENT_ID=取得したクライアントID
FACEBOOK_CLIENT_SECRET=取得したシークレットキー
FACEBOOK_REDIRECT_URI=https://localhost/social-login/public/login/facebook/callback

GOOGLE_CLIENT_ID=取得したクライアントID
GOOGLE_CLIENT_SECRET=取得したシークレットキー
GOOGLE_REDIRECT_URI=https://localhost/social-login/public/login/google/callback

TWITTER_CLIENT_ID=取得したクライアントID
TWITTER_CLIENT_SECRET=取得したシークレットキー
TWITTER_REDIRECT_URI=https://localhost/social-login/public/login/twitter/callback

LINE_CLIENT_ID=取得したクライアントID
LINE_CLIENT_SECRET=取得したシークレットキー
LINE_REDIRECT_URI=https://localhost/social-login/public/login/line/callback

```

##14.動作確認

これでソーシャルログイン機能ができたはずなので、

`https://localhost/social-login/public/login/(ログインしたいSNS名)`にアクセスすると、ソーシャルログインができるはずです。

お疲れさまでした。

#参考にさせていただいた記事

Laravel Socialiteでソーシャルログイン
https://tdomy.com/2020/08/how-to-use-laravel-socialite/

socialiteを使ったOAuth認証の実装
https://note.com/kodokuna_dancer/n/n9556f4ad17f2

<br>