Laravel6でTwitterログインを実装する

この記事ではLaravel6でTwitterログインを実装する手順を解説していきます。

メモ程度ですが、悪しからず。

##Twitter Developerの登録

まずはTwitter Developerにてアプリを作成してください。

##env.ファイルの作成
とりあえずTwitterAPIを使う時の初期設定。

```
TWITTER_CLIENT_ID=
TWITTER_CLIENT_SECRET=
TWITTER_CLIENT_ID_ACCESS_TOKEN =
TWITTER_CLIENT_ID_ACCESS_TOKEN_SECRET =
CALLBACK_URL=http://127.0.0.1:8000/login/twitter/callback
```
空白の箇所は自分のやつを入れる。

##config/service.phpに処理追加
今回は必要ないけど、とりあえず追加しておく。
envファイルから呼び出すわけにはいかないので、config経由するための記述。
 
```
'twitter' => [
       'client_id' => env('TWITTER_CLIENT_ID'),
       'client_secret' => env('TWITTER_CLIENT_SECRET'),
       'access_token' => env('TWITTER_CLIENT_ID_ACCESS_TOKEN', ''),
       'access_token_secret' => env('TWITTER_CLIENT_ID_ACCESS_TOKEN_SECRET', ''),
       'redirect' => env('CALLBACK_URL')
    ],
```

##config/appに処理追加
下記を追加する。
サービスプロバイダへ登録して、コンテナに登録する。
あとエイリアスにも追加する。

```
    'providers' => [
        ~省略~
        Laravel\Socialite\SocialiteServiceProvider::class, //Socialiteを使う設定

    ],

    'aliases' => [
        ~省略~
        'Socialite' => Laravel\Socialite\Facades\Socialite::class,//Socialiteを使う設定

    ],
```

##Socialiteをインストール
```
composer require laravel/socialite
```

Socialiteについては[Laravel6ドキュメント](https://readouble.com/laravel/6.x/ja/socialite.html)を見るべし。

##ルーティングの追加

```
Route::get('login/twitter', 'Auth\LoginController@redirectToTwitterProvider');
Route::get('login/twitter/callback', 'Auth\LoginController@handleTwitterProviderCallback');
```

##Loginコントローラーに処理を追加

とりあえずここまで。

```
    use Socialite;

    ~省略~

    public function redirectToTwitterProvider()
   {
       return Socialite::driver('twitter')->redirect();
   }

    public function handleTwitterProviderCallback()
    {
        $user = Socialite::driver('Twitter')->user();
        dd($user);
    }
```

##テーブルの作成

```
php artisan make:migration create_social_users --create social_users
```

中身は次の通り。

```
Schema::create('social_users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->bigInteger('user_id')->unsigned()->index();
            $table->string('provider_user_id')->index();
            $table->timestamps();

            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');
        });
```

##usersテーブルの拡張

```
php artisan make:migration add_social_columns_to_users --table users
```

中身は次の通り。

```
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('unique_id')->after('id');
            $table->string('avatar')->after('password');
            $table->text('bio')->after('avatar');
            $table->string('email')->nullable()->change();
            $table->string('password')->nullable()->change();
        });
    }

    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('password')->change();
            $table->string('email')->change();
            $table->dropColumn('bio');
            $table->dropColumn('avatar');
            $table->dropColumn('unique_id');
        });
    }
```

##マイグレーションの実行
下記をインストール。
カラム属性を変更する時は必要。

```
composer require doctrine/dbal
```
もしエラーが出たら、バージョンを指定すればOK。

次にマイグレーション実行。

```
php artisan migrate
```

##モデルの作成

```
php artisan make:model SocialUser
```
<br>
リレーションも追加しておく。
まずはUserモデル。

```
    public function socialUsers()
    {
        return $this->hasMany(SocialUser::class);
    }
```

下記も。

```
    public function user()
    {
        return $this->belongsTo(User::class);
    }
```

##Loginコントローラーに処理追加。

```
<?php

namespace App\Http\Controllers\Auth;

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

use Socialite;

class LoginController extends Controller
{

    use AuthenticatesUsers;

    protected $redirectTo = RouteServiceProvider::HOME;

    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    public function redirectToTwitterProvider()
    {
        return Socialite::driver('twitter')->redirect();
    }

    public function handleTwitterProviderCallback()
    {
        $providerUser = Socialite::driver('Twitter')->user();


        // 既に存在するユーザーかを確認
        $socialUser = SocialUser::where('provider_user_id', $providerUser->id)->first();

        if ($socialUser) {
            // 既存のユーザーはログインしてトップページへ
            Auth::login($socialUser->user, true);
            return redirect('/');
        }

        // 新しいユーザーを作成
        $user = new User();
        $user->unique_id = $providerUser->nickname;
        $user->name = $providerUser->name;
        $user->avatar = $providerUser->user['profile_image_url_https'];
        $user->bio = $providerUser->user['description'];

        $socialUser = new SocialUser();
        $socialUser->provider_user_id = $providerUser->id;

        DB::transaction(function () use ($user, $socialUser) {
            $user->save();
            $user->socialUsers()->save($socialUser);
        });

        Auth::login($user, true);
        return redirect('/');
    }
}
```

##参考
[Laravel Socialiteを使ってTwitterアカウントでログイン機能](https://crieit.net/posts/Laravel-Socialite-Twitter)
[Laravel6.0+SocialiteでTwitterログインを実装する](https://note.com/mukae9/n/n91ff7bccfcd8)