【Jetstream】Laravel8 SocialiteでLINEログイン機能を実装してみる


## Laravel Socialite

![20220830_140454_2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/bb709d7e-ffe2-215f-9a47-8a8cfbffee2f.jpeg)

・OAuth認証で俗にいうログインパッケージ。
・LINE、Facebook、Twitter、Google、GitHub、Instagram、等に対応。


仕事でちょっと使う機会があり各サイトのDeveloperへの登録の仕方も含めて
使い方を備忘録的に書いていきたいと思います。

基本的にSNS側のDeveloperサイトでは下記を設定。(名称はSNS毎に微妙に異なる)

・チャネルID
・チャネルシークレット
・コールバックURL 

上記3点をlarvelの .envファイルに記載して使うイメージ。



### 【各SNS Developer側から返ってくるユーザ情報一覧】
![laravel-socialite-returnユーザ情報.xlsx - Excel 2022-08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/7ae26f5e-c79a-5eac-dc1b-321fbe1ed594.png)

これを見ると下記3つのユーザ情報が上記6つのSNSでは返って来るようです。
SNSによってname or nickname だけ返って来るといった感じでしょうか。

id
email
avatar

※Facebook 、Githubは下記サイトの「Returned User fields」が未記載だったので
dd($user)　で確認。

https://socialiteproviders.com/Line/#installation-basic-usage





## ～ 2021年　ソーシャルログイン動向 ～

・2021年最も利用ユーザー数が多かったのはLINEログイン（76％）
・6種実装サイトでの利用ユーザー数は、1位がLINEログインで32%、2位がYahoo! JAPANログインで30%
・デバイス別ではスマートフォンでの利用が9割以上で、2019年比での伸び率は197％

![2021年1月～2021年12月のソーシャルログイン利用状況222.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/a74c85ff-8f41-3ad3-cfd7-797b4a7caa33.png)

何だかんだで利用ユーザ数の多い
LINEをソーシャルログインで実装すれば間違いはなさそうです。

ソーシャルログイン利用状況調査2021
https://socialplus.jp/report/2021


## 【環境】

・Windows11 pro
・laravel ^8.75
・php": "^7.3
・laravel/jetstream: "2.1
・laravel/socialite　: ^5.0


## 【前提条件】

・laravel、jetstream設定が終わり起動済。
・composer をインストール済。


## 【SNS側のDeveloperサイトでの設定】

今回は [developers.LINE](https://developers.line.biz/console/) の設定をメインに記載します。
(他のSNS側のdevelopersの設定は時間があれば書きたいと思います。)
※LINE / Twitter / Facebook　はTel登録の必要あり



![LINE Developers1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/58676c33-ba02-46dc-96c5-9b2a6fd68c24.png)
プロバイダーを作成ボタン
![LINE Developers — プロバイダーを作成ボタン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/e250f59b-b079-5569-35d8-b8de3dbe9fb4.png)
「プロバイダー名」を入力して作成ボタン

![LINE Developers — LINEログイン」を選択.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/d8afc0b1-6cf9-b595-c591-3176ffb466e0.png)
「LINEログイン」を選択

![LINE Developers — Mozilla Firefox 2022-09-01 12.46.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/3679b345-6a3d-f044-fc38-42655a79b236.png)

・チャネルの種類　→　「LINEログイン」

・プロバイダー　→　そのまま

・サービスを提供する地域　　　→「日本」
・会社・事業者の所在国・地域　→「日本」


![LINE Developers — Mozilla Firefox 2022-09-01 12.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/92d76b84-bf8d-57ab-d439-fa423500c2a5.png)

・チャネルアイコン　→任意の画像を入力
・チャネル名　→任意の値を入力
・チャネル説明　→任意の値を入力


![LINE Developers — Mozilla Firefox 2022-09-01 12.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/38ecea78-fa0a-1d24-33b8-4ebb22b21dec.png)

・アプリタイプ　　→　「ウェブアプリ」を入力
・メールアドレス　→　任意の値を入力

![LINE Developers — Mozilla Firefox 2022-09-01 12.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/5cb6200e-7edc-be03-17db-1e0852e7389a.png)
・公開ステータス 　→　「開発」→　「公開済」
・コールバックURL 　→　laravelのenvファイルと同じコールバックURLを入力。


![LINE Developers7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/c581018d-3d60-148a-6582-5220d1df31cd.png)
・チャネルシークレット　→　laravelのenvファイルにコピペ。


![LINE Developers — OpenID Connect　メールアドレス取得権限.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/331dbc49-f8d2-4d60-521a-a7e7fa035bfc.png)
・OpenID Connect　メールアドレス取得権限　→　申請ボタン押下

![LINE Developers — メールアドレス取得権限2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/1c195935-91a2-70a8-782c-fc8a3085aebf.png)
・チェックを入れて、画面のスクリーンショットを取って、その画像をアップロード

![LINE Developers — ステータスが「申請済み」に.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/39fc999e-dcd3-1e1e-38cd-b84e33518c6e.png)
・ステータスが「申請済み」に


LINE Developersの設定はこれで完了。

■　他のSNS側のdeveloper (アカウント作成済である事)
設定はLINEのとさほど変わらないので適当にやれば出来るはず。。

・[Google cloud](https://console.cloud.google.com/apis/credentials)
・[developer.twitter](https://developer.twitter.com/en/portal/dashboard)
・[developer.github](https://github.com/settings/applications)
・[developers.facebook](https://developers.facebook.com/apps/)
・[developers.yahoo](https://e.developer.yahoo.co.jp/dashboard/)


##### ngrokを使ってlocalhostを公開サーバのように出来るツール

ngrokの使い方（windows版）
https://qiita.com/backstreet/items/b21ce6439ef48d223ddf

localhostで動いているシステムを、
公開サーバ上のようにアクセスできるツールです。

ここで設定した公開用URLを
各SNSのdeveloper側でコールバックurlとして設定すると便利です。


:::note info
コールバックurlを「localhost」で設定するとうまく動作しないものがあるのでこっちのほうが良いかも
:::



## 【Laravel側での設定】

##### Githubに作業ソースを上げています

:::note info
[Github](https://github.com/silversink8888/laravel8-inertiajs-socialite-)
:::


##### laravel Socialite 、各メディアのプロバイダーをインストール

```
composer require laravel/socialite

composer require socialiteproviders/line
composer require socialiteproviders/twitter
composer require socialiteproviders/yahoo
composer require socialiteproviders/google
composer require socialiteproviders/facebook
```

##### チャネルID、チャネルシークレット、コールバックURL の設定
```.env
LINE_CHANNEL_ID=XXXXXXXXXXXXXX
LINE_CHANNEL_SECRET=XXXXXXXXXXXXXX
LINE_REDIRECT='https://XXXXXXXXXXXXXX/login/line/callback'
```


```config/services.php
'line' => [
    'client_id'     =>env('LINE_CHANNEL_ID'),
    'client_secret' =>env('LINE_CHANNEL_SECRET'),
    'redirect'      =>env('LINE_REDIRECT'),
],
```



##### ルーティングの設定

```routes/web.php
Route::prefix('login/{provider}')->where(['provider' => '(line|google|twitter|facebook|yahoo|github)'])->group(function(){
    Route::get('/',         [LoginController::class, 'redirectToProvider']);
    Route::get('/callback', [LoginController::class, 'handleProviderCallback']);
});
```

/login/line
→LINE Developersにサーバ情報を下さいリダイレクト

/login/line/callback
→LINE Developersから送られてくるサーバ情報を受け取る



##### プロバイダの設定

```config/app.php
'providers' => [
    \SocialiteProviders\Manager\ServiceProvider::class,   // 追加
],

'aliases' => [
        'Socialite' => Laravel\Socialite\Facades\Socialite::class,  // 追加
```
```app\Providers\EventServiceProvider.php
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        //追加　ここから
        \SocialiteProviders\Manager\SocialiteWasCalled::class => [
            'SocialiteProviders\\Line\\LineExtendSocialite@handle',
            'SocialiteProviders\\Twitter\\TwitterExtendSocialite@handle',
            'SocialiteProviders\\Facebook\\FacebookExtendSocialite@handle',
            'SocialiteProviders\\Google\\GoogleExtendSocialite@handle',
            'SocialiteProviders\\Yahoo\\YahooExtendSocialite@handle',
        
        ],
        //追加　ここまで

    ];
    
    
```

##### ユーザーテーブルに各SNSのidを保存するカラムを追加

migrationファイル作成
```
php artisan make:migration add_sns_id_to_users_table
```

下記のように編集
```database\migrations\2022_08_26_021730_add_sns_id_to_users_table.php
<?php


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


class AddSocialiteIdToUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table("users", function (Blueprint $table) {
            // 追加
            $table->string("provider")->after('password')->nullable();
            $table->string("line_id")->after('provider')->nullable();
            $table->string("google_id")->after('line_id')->nullable();
            $table->string("facebook_id")->after('google_id')->nullable();
            $table->string("yahoo_id")->after('facebook_id')->nullable();
            $table->string("twitter_id")->after('yahoo_id')->nullable();
            $table->string("github_id")->after('twitter_id')->nullable();
        });
    }


    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table("users", function (Blueprint $table) {
            // 追加
            $table->dropColumn('provider'); //SNS判別用
            $table->dropColumn('line_id');
            $table->dropColumn('google_id');
            $table->dropColumn('facebook_id');
            $table->dropColumn('yahoo_id');
            $table->dropColumn('twitter_id');
            $table->dropColumn('github_id');
        });
    }
}
```
マイグレーション
```
php artisan migrate
```
##### Userモデルのホワイトリストに追加したSNSのカラムを追加
```app\Models\User.php
    protected $fillable = [
        'name',
        'email',
        'password',
        'provider',
        "line_id",
        "google_id",
        "facebook_id",
        "yahoo_id",
        "twitter_id",
        "github_id",
    ];
```


##### Loginコントローラの作成の設定

Laravel8からはログイン関連は
Loginコントローラはなくなったので新しく作成。

```
php artisan make:controller Auth\\LoginController
```


```app\Http\Controllers\Auth\LoginController.php
<?php
namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Http\Request;
use Laravel\Socialite\Facades\Socialite;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Auth;

class LoginController extends Controller {

    // SNSのOAuth側へリダイレクト
    public function redirectToProvider(Request $request) {
        $provider = $request->provider;
     //   dd($provider);

        return Socialite::driver($provider)->redirect();
    }

    // SNS側からcallbackされるユーザー情報
    public function handleProviderCallback(Request $request) {
        try {
            $provider = $request->provider;
            $sns_user = Socialite::driver($provider)->user();
        //    dd($sns_user);

            $sns_email = '';
            $sns_name = '';
            $sns_nickname = '';

            //各SNSのID
            $line_id = '';
            $google_id = '';
            $facebook_id = '';
            $yahoo_id = '';
            $twitter_id = '';
            $github_id = '';

            $sns_email = $sns_user->getEmail();
            $sns_name  = $sns_user->getName();
            $sns_nickname  = $sns_user->getNickname();
            if(!$sns_name){ $sns_name = $sns_nickname;} // github用の処理 (nicknameしかないので)
        //    dd($provider);
        //    dd($sns_email);


            if($provider == 'line'){
                $line_id = $sns_user->getId();
            }elseif($provider == 'google'){
                $google_id = $sns_user->getId();
            }elseif($provider == 'twitter'){
                $twitter_id = $sns_user->getId();
            }elseif($provider == 'github'){
                $github_id = $sns_user->getId();
            }elseif($provider == 'facebook'){
                $facebook_id = $sns_user->getId();
            }elseif($provider == 'yahoo'){
                $yahoo_id = $sns_user->getId();
            }

            $provider_culmn='';
            $provider_culmn = $provider . "_id";


            //  $user = Socialite::driver("google")->user();
                $finduser = User::where($provider_culmn, $sns_user->getId())->first();

                if ($finduser) {
                    Auth::login($finduser);
                    return redirect()->intended("dashboard");
                } else {
                    $newUser = User::create([
                        'email'    => $sns_email, 
                        'name'     => $sns_name, 
                        'provider' => $provider, 
                        'line_id'  => $line_id,
                        'google_id'  => $google_id,
                        'yahoo_id'  => $yahoo_id,
                        'twitter_id'  => $twitter_id,
                        'github_id'  => $github_id,
                        'facebook_id'  => $facebook_id,
                        'password' => Hash::make(Str::random())
                    ]);

                    Auth::login($newUser);

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

```


##### ログイン画面にソーシャルログインボタンを設定 (Jetstream Inertia.jsなのでvueです)
```resources\js\Pages\Auth\Login.vue
<div class="flex items-center">
    <jet-button class="ml-0 bg-green-500 w-80">
        <a href="login/line">
            Login with LINE
        </a>
    </jet-button>
</div>
```



##### LINEでログインしてみると

![login1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/5d923f85-a0c7-5554-d2bb-ecc936913ea2.png)

LINEログイン画面にリダイレクト
![login2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/0253f761-9571-25ab-7b9d-4c65a12a6882.png)

dashboard画面に切り替わり、右上に名前が表示されています。
![login3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/38ccab8a-651c-ce54-edd6-f91b87d78a77.png)

phpmyadminの中を確認してみると、、
![login4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/669259/3cf5a01a-7f79-8bce-9f59-14db4bcdf495.png)

どうやらLINEログイン出来たようです。


##### SNS認証後に、返されるユーザー情報。

```
$user = Socialite::driver($provider)->user();    // Email
dd($user);

$user->getId();  　　　 // ID  (各SNSのユーザ固有のID)
$user->getNickname();   // 名前 (github等の名前で使われている)
$user->getName();       // 名前
$user->getEmail();      // Email
$user->getAvatar();     // プロフィール画像のURL
```



## 【備考】

docker上では何故かLINEとの連携が出来なかったので
通常のlocalhostで起動。

Windows上だと連携が出来ない等の報告があるようです。
何か情報をお持ちの人いれば教えてください。

https://teratail.com/questions/285618
https://biz.addisteria.com/laravel_line_integration/

ありがとうございました。
誤字・記載ミス等ありましたらメッセージ下さい。