PHP
Laravel
Socialite

Laravel 5.3で外部アカウントを使用した認証機能を実装する方法

More than 1 year has passed since last update.


  • LaravelではfacebookやtwitterのOAuth認証によるログイン機能を実現するためのパッケージ「laravel/socialite」が存在する。

  • 日本国内向けのサービス(LINEやYahoo!JAPAN)を使った認証はサポートされていないが、これについてはこちらのポストで。


追記


  • 2017.05.19


SocialController::createOrGetUser()において、各種サービスから取得したメールアドレスを保存していたが、make:authを使って作成する認証方式を併用する場合に、SNS登録メールアドレスとバッティングしてログインできなくなる事象があったため、該当箇所をコメントアウトしました。



前提


導入手順


laravel/socialiteパッケージを取得



  • composer requireでパッケージを取得する。

    cd (/your/laravel/project/path)
    
    composer require laravel/socialite



  • config/app.phpを編集する


    config/app.php

    <?php

    return [
    ...
    'providers' => [
    ...
    //laravel/socialite
    Laravel\Socialite\SocialiteServiceProvider::class,
    ...
    ],
    ...
    'aliases' => [
    ...
    //laravel/socialite
    'Socialite' => Laravel\Socialite\Facades\Socialite::class,
    ...
    ],

    ];





socialiteの設定



  • 各OAuthサービスごとに、ID,トークンや認証処理後のコールバックURLなどを指定する必要がある。



    • config/services.phpを編集する。


      config/services.php

      <?php

      return [
      ...
      //Socialite認証
      'twitter' => [
      'client_id' => env('TWITTER_CLIENT_ID'),
      'client_secret' => env('TWITTER_CLIENT_SECRET'),
      'redirect' => env('TWITTER_REDIRECT'),
      ],
      'facebook' => [
      'client_id' => env('FACEBOOK_CLIENT_ID'),
      'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
      'redirect' => env('FACEBOOK_REDIRECT'),
      ],
      'google' => [
      'client_id' => env('GOOGLE_CLIENT_ID'),
      'client_secret' => env('GOOGLE_CLIENT_SECRET'),
      'redirect' => env('GOOGLE_REDIRECT'),
      ],
      ];





    • .env.xxxxxを編集


      env.xxxxx

      ...
      
      TWITTER_CLIENT_ID=(twitter-client-id)
      TWITTER_CLIENT_SECRET=(twitter-client-secret)
      TWITTER_REDIRECT=(twitter-redirect-url)

      FACEBOOK_CLIENT_ID=(facebook-client-id)
      FACEBOOK_CLIENT_SECRET=(facebook-client-secret)
      FACEBOOK_REDIRECT=(facebook-redirect-url)

      GOOGLE_CLIENT_ID=(google-client-id)
      GOOGLE_CLIENT_SECRET=(google-client-secret)
      GOOGLE_REDIRECT=(google-redirect-url)
      ...







テーブル&モデル作成



  • 認証に使用するテーブルを作成する



    • migration作成

      cd your/laravel/project/path
      
      php artisan make:migration create_social_accounts_table


      database/migrations/xxxx_xx_xx_xxxxxx_social_accounts.php

      <?php

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

      class CreateSocialAccountsTable extends Migration
      {
      /**
      * Run the migrations.
      *
      * @return void
      */

      public function up()
      {
      Schema::create('social_accounts', function (Blueprint $table) {
      $table->increments('id');
      $table->integer('user_id')->unsigned()->nullable();
      $table->string('provider_user_id');
      $table->mediumText('provider_access_token')->nullable();
      $table->string('provider');
      $table->timestamps();
      $table->softDeletes();
      });
      }

      /**
      * Reverse the migrations.
      *
      * @return void
      */

      public function down()
      {
      Schema::drop('social_accounts');
      }
      }





    • usersテーブルの定義修正


      database/migrations/2014_10_12_000000_create_users_table.php

      <?php

      // ...

      class CreateUsersTable extends Migration
      {
      // ...

      public function up()
      {
      Schema::create('users', function (Blueprint $table) {
      // ...
      // $table->string('email')->unique(); // -
      // $table->string('password'); // -
      $table->string('email')->nullable(); // +
      $table->string('password')->nullable(); // +
      // ...
      });
      }

      //...
      }



      • 認証に使用するサービスによって、取得できる項目は違うため、このへんのnullable対応は必要に応じて実施する。




    • テーブル作成

      cd your/laravel/project/path
      
      php artisan migrate:refresh





  • 認証に使用するテーブルのモデルを用意する。


    app/SocialAccount.php


    <?php

    namespace App;

    use Illuminate\Database\Eloquent\Model;

    class SocialAccount extends Model
    {
    protected $table = 'social_accounts';

    protected $primaryKey = 'id';

    /**
    * The attributes that are mass assignable.
    *
    * @var array
    */

    protected $fillable = [
    'user_id',
    'provider_user_id',
    'provider_access_token',
    'provider',
    ];

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





コントローラ作成



  • 認証に使用するコントローラを作成する


    app/Http/Controllers/Auth/SocialController.php

    <?php
    
    namespace App\Http\Controllers\Auth;

    use App\Http\Controllers\Controller;
    use Illuminate\Http\Request;
    use Auth;
    use Socialite;

    use App\User;
    use App\SocialAccount;

    class SocialController extends Controller
    {
    protected $redirectTo = '/home'; //your-redirect-url-after-login

    // twitter

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

    public function getTwitterAuthCallback()
    {
    $twitterUser = Socialite::driver('twitter')->user();

    $user = $this->createOrGetUser($twitterUser, 'twitter');
    Auth::login($user, true);

    return redirect($this->redirectTo);
    }

    // facebook

    public function getFacebookAuth()
    {
    return Socialite::driver('facebook')->redirect();
    }

    public function getFacebookAuthCallback()
    {
    $facebookUser = Socialite::driver('facebook')->stateless()->user(); // (1)

    $user = $this->createOrGetUser($facebookUser, 'facebook');
    Auth::login($user, true);

    return redirect($this->redirectTo);
    }

    // Google

    public function getGoogleAuth()
    {
    return Socialite::driver('google')->redirect();
    }

    public function getGoogleAuthCallback()
    {
    $googleUser = Socialite::driver('google')->user();

    $user = $this->createOrGetUser($googleUser, 'google');
    Auth::login($user, true);

    return redirect($this->redirectTo);
    }

    public function createOrGetUser($providerUser, $provider)
    {
    $account = SocialAccount::firstOrCreate([
    'provider_user_id' => $providerUser->getId(),
    'provider' => $provider,
    ]);

    if (empty($account->user))
    {
    $user = User::create([
    'name' => $providerUser->getName(),
    // 'email' => $providerUser->getEmail(), # 削除 (2017.05.19)
    'avatar' => $providerUser->getAvatar(),
    ]);
    $account->user()->associate($user);
    }

    $account->provider_access_token = $providerUser->token;
    $account->save();

    return $account->user;
    }
    }





ルーティング設定



  • routes/web.phpに追加


    routes/web.php

    ...
    
    //twitter
    Route::get('/login/twitter', 'Auth\SocialController@getTwitterAuth');
    Route::get('/login/twitter/callback', 'Auth\SocialController@getTwitterAuthCallback');

    //facebook
    Route::get('/login/facebook', 'Auth\SocialController@getFacebookAuth');
    Route::get('/login/facebook/callback', 'Auth\SocialController@getFacebookAuthCallback');

    //google
    Route::get('/login/google', 'Auth\SocialController@getGoogleAuth');
    Route::get('/login/google/callback', 'Auth\SocialController@getGoogleAuthCallback');
    ...





導線作成


  • どこかしらのビューに、認証用URLへの導線を張る


any.view.blade.php

...

(例)
<div class="container">
<div class="btn-group btn-group-justified">
<a class="btn btn-default" href="/login/facebook">
facebook
</a>
<a class="btn btn-default" href="/login/twitter">
twitter
</a>
<a class="btn btn-default" href="/login/google">
google
</a>
</div>
</div>
...