Laravel6.x Twitterログイン

LaravelでSocialiteをしようしてTwitter認証機能を実装してしたので備忘録として書いておきます。

##実装環境
* PHP7.3
* Laravel 6.20.26



##手順
1.アクセストークン・シークレットトークンの取得
2.Socialiteをインストール
3.usersテーブルにtwitter情報を保存するカラムの追加
4.Controllerを作成し、twitterログインを実装







##1.アクセストークン、シークレットの取得
[Laravel deveroper](https://developer.twitter.com/en/portal/register/playground)でアカウントを作成いて、アクセストーク、シークレットトークンの取得をします。
アカウント作成の際審査があり少し大変のなので[こちら](https://digitalnavi.net/internet/3072/)を参考にアカウントを作成しました。


##2.Socialiteをインストール
Composerをしようしてターミナル上で下記のコマンドを実行してSocialiteをインストールする。

```terminal:terminal
composer require laravel/socialite
```
インストール後は`config/app.php`のprovidersとaliasの設定をする

```php:config/app.php
'providers' => [ 
    Laravel\Socialite\SocialiteServiceProvider::class,
],

'aliases' => [
    'Socialite' => Laravel\Socialite\Facades\Socialite::class,
]

```
1.で取得してたTwitterのシークレットトークンとアクセストークンとコールバックurl（oauth認証で取得したtwitter情報を受け取る処理）を.envに設定

```:.env
TWITTER_CLIENT_ID=twitterシークレットトークン
TWITTER_CLIENT_SECRET=twitterアクセストークン
CALLBACK_URL=コールバックURL
```
oauthの認証情報を`config/services.php`に設定

```php:config/services.php
'twitter' => [
    'client_id' => env('TWITTER_CLIENT_ID'),
    'client_secret' => env('TWITTER_CLIENT_SECRET'),
    'redirect' => env('CALLBACK_URL'),
],
```

##3.usersテーブルにtwitter情報を保存するカラムの追加
twitter情報を追加するためのカラムを追加しておく。

```terminal
php artisan make:migration add_twitter_id_to_users_table --table=users
```
今回はtwitterのidだけを保存するようにする。メールアドレスとパスワードも保存しないのでnullabeをしていしておく。

```php:database/migrations/日付_add_twitter_id_users_table
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddTwitterIdToUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('email')->nullable()->change();
            $table->string('password')->nullable()->change();
            $table->string('twitter_id')->nullable();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            //
        });
    }
}
```
twitter_idが保存できるようにUserモデルの$fillableにtwitter_idを追加しておく

```php:app/User.php
~省略~

 protected $fillable = [
        'name', 'email', 'password',  'self_introduction', 'sex', 'img_name', 'twitter_id'
  ];

~省略~
```


## 4.Controllerを作成し、twitterログインを実装
Controllerの作成

```terminal
php artisan make:controller Auth/TwitterController
```

ルーティングの設定

```php:routes/web.php
Route::group(['prefix' => 'twitter', 'middleware' => 'guest'], function () {
      Route::get('login', 'Auth\TwitterController@redirectToProvider')->name('twitter.login'); //oauth認証を行うurl
      Route::get('login/callback', 'Auth\TwitterController@handleProviderCallback')->name('twitter.callback'); //認証情報をうけとる処理
 });
```

oauth認証、新規登録,ログイン処理を記述

```php:app/Http/Controllers/Auth/TwitterController.php
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Http\File;
use Illuminate\Support\Facades\Storage;  
use Illuminate\Support\Facades\Auth;
use Intervention\Image\Facades\Image;
use Socialite;
use App\User;

class TwitterController extends Controller
{
    //twitter認証へリダイレクト
    public function redirectToProvider()
    {
        return Socialite::driver('twitter')->redirect();
    }

    //twitterからユーザー情報受け取る
    public function  handleProviderCallback()
    {
        try {
            $oauth_user = Socialite::driver('twitter')->user();
        } catch (Exeption $e){
            return redirect('/');
        }


        $user = $this->findOrCreateUser($oauth_user);
        Auth::login($user);
        return redirect()->route('home');
    }

    //新規登録またはユーザーログイン
    public function findOrCreateUser($oauth_user)
    {
        //新規登録かログインなのかを判定する
        $user =  User::where('twitter_id', $oauth_user->id)->first();
        $avatar_name = $oauth_user->avatar != null ? basename($oauth_user->avatar) : '';
        
        //ログインユーザーの場合
        if (!is_null($user)) {
            //ユーザー名の変更があれば変更
            $user->name = $oauth_user->name;
            $user->save();
            return $user;
        }

        //新規登録の場合
        if (!empty($avatar_name)) {
            $this->imgUpload($oauth_user->avatar);
        }

        $new_user = User::create([
            'name' => $oauth_user->name,
            'img_name' => $avatar_name, 
            'twitter_id' => $oauth_user->id,
        ]);

        return $new_user;
    }

    //画像のアプロ-ド
    public function imgUpload($avatar)
    {
        $file_name = basename($avatar);
        $img = Image::make(file_get_contents($avatar));
        return $img->resize(400, 400)->save(storage_path() . '/app/public/images/' . $file_name);
    }
}

```

解説
まずredirectToProvider()メソッドの`Socialite::driver('twitter')->redirect()`でtwitterのoauthプロバイダへリダイレクトします。
[redirect()](https://readouble.com/laravel/6.x/ja/socialite.html#routing)について

```php
    //twitter認証へリダイレクト
    public function redirectToProvider()
    {
        return Socialite::driver('twitter')->redirect();
    }
```

twitterでの認証が成功するとコールバックURLとして設定しておいた`handleProviderCallback()`メソッドへリダイレクトされます。認証後`Socialite::driver('twitter')->user();`を事項するとtwitterの各種ユーザー情報を取得することができます。その情報をもとにユーザーの新規作成、ログインなどの処理を実行する。

```php
    //twitterからユーザー情報受け取る
    public function  handleProviderCallback()
    {
        try {
            $oauth_user = Socialite::driver('twitter')->user();
        } catch (Exeption $e){
            return redirect('/');
        }


        $user = $this->findOrCreateUser($oauth_user);
        Auth::login($user);
        return redirect()->route('home');
    }
```

新規登録、ログインの処理
twitterのidを新規作成の際に保存し、ログインの判定をそのidが存在するのかで判断する。

```php
    //新規登録またはユーザーログイン
    public function findOrCreateUser($oauth_user)
    {
        //新規登録かログインなのかを判定する
        $user =  User::where('twitter_id', $oauth_user->id)->first();
        $avatar_name = $oauth_user->avatar != null ? basename($oauth_user->avatar) : '';

        //ログインユーザーの場合
        if (!is_null($user)) {
            //ユーザー名の変更があれば変更
            $user->name = $oauth_user->name;
            $user->save();
            return $user;
        }

        //新規登録の場合
        if (!empty($avatar_name)) {
            $this->imgUpload($oauth_user->avatar);
        }

        $new_user = User::create([
            'name' => $oauth_user->name,
            'img_name' => $avatar_name, 
            'twitter_id' => $oauth_user->id,
        ]);

        return $new_user;
    
```
　
twitterのアイコン画像を保存する処理

```php
    //画像のアプロ-ド
    public function imgUpload($avatar)
    {
        $file_name = basename($avatar);
        $img = Image::make(file_get_contents($avatar));
        return $img->resize(400, 400)->save(storage_path() . '/app/public/images/' . $file_name);
    }

```