サイトアイコン IT NEWS

【Laravel】SocialiteでSNSアカウントでソーシャルログイン認証

laravel-socialite

今回は、LaravelSocialiteを使って、GoogleFacebookSNSアカウントを利用したソーシャルログイン認証について説明します。
なぜこの2つかと言うと、複数のSNSを使った場合の効率の良い導入方法の紹介と、単純に有名なSNSかつメールアドレスを取得できること。

Socialiteでソーシャルログイン認証

Twitterのようにメールアドレスが取得できないと後々不便になるから導入しません。(経験則です)
あと、SNSからはログイン認証に必要な最低限のデータのみ取得することにします。
基本的に少しコードを追加するだけなので、電話番号とかアバターなどを取得したい方は別途調べてください。

事前準備(SNSの設定)

LaravelSocialiteパッケージでソーシャルログイン認証をするには、まずは各SNSの開発者(Developers)画面から、クライアントID(アプリID)やシークレットIDを取得し、コールバックURLの設定を行ってください。
そしてそれらの情報を設定ファイルに入力しておきましょう。

以下の3つの情報をSNS毎に設定ファイルに記載します。

  • client_id・・・クライアントID
  • client_secret・・・シークレットID
  • redirect・・・コールバックURL(認証後に遷移するページ)

/config/services.php

ここでは、必要な情報を格納する変数を設定します。
実際の設定値は、次の設定ファイル(.env)に記載します。

/**
* socialite Settings
*/
'facebook' => [
    'client_id'     => env('FACEBOOK_API_ID'),
    'client_secret' => env('FACEBOOK_API_SECRET'),
    'redirect'      => env('FACEBOOK_CALLBACKURL'),
],

'google' => [
    'client_id'     => env('GOOGLEPLUS_API_ID'),
    'client_secret' => env('GOOGLEPLUS_API_SECRET'),
    'redirect'      => env('GOOGLEPLUS_CALLBACKURL'),
],

.env

実際の値は[.env]ファイルに記載します。

FACEBOOK_API_ID=XXXXXXXXXXXXXXXX
FACEBOOK_API_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
FACEBOOK_CALLBACKURL=https://[your domain]/login/facebook/callbackGOOGLEPLUS_API_ID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.apps.googleusercontent.com
GOOGLEPLUS_API_SECRET=XXXXXXXXXXXXXXXXXXXXXXXXX
GOOGLEPLUS_CALLBACKURL=https://[your domain]/login/google/callback

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

LaravelGitHubにも入っているパッケージSocialite」をインストールしてソーシャルログイン認証を行います。

まずは、いつも通り[composer require]します。

composer require laravel/socialite

Socialiteを有効にする

次に、設定ファイルのprovidersaliasesに[Socialite]追記します。

/config/app.php

'providers' => [
    ...
    /*
     * Package Service Providers...
     */
    Laravel\Socialite\SocialiteServiceProvider::class,
],

'aliases' => [
    ...
    /*
     * Packages aliases...
     */
    'Socialite' => Laravel\Socialite\Facades\Socialite::class,
],

これでSocialiteの準備は完了です。

SNSアカウント用のテーブル作成

SNSアカウントログインする場合は、パスワード(場合によってはメールアドレス)が不要になるので、既存のUsersテーブルを変更しなければなりません。
変更するためにはDoctrinedbalDatabase Abstraction Layer)なるものが必要らしいです。(ココちょっとハマった)

これも[composer require]します。

composer require doctrine/dbal

次に、Usersテーブルを変更するためのLaravel標準のマイグレーションファイルを作成し、

php artisan make:migration update_users_table --table users

以下のように書きます。

/database/migrations/…_update_users_table.php

<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class UpdateUsersTable 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();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        //
    }
}

ここまででUsersテーブルを変更する準備が完了しました。
次は、Usersテーブルと紐付くSNSアカウントの情報を登録するテーブルモデルを作成していきます。
ここもコマンドでパパっと!

php artisan make:model SocialAccount --migration

モデルと一緒にマイグレーションファイルも以下のように作成します。

/database/migrations/…_create_social_accounts_table.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')->nullable();
            $table->string('provider');
            $table->string('provider_id');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('social_accounts');
    }
}

/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_id',
        'provider',
    ];

    public function user()
    {
        return $this->belongsTo('AppUser');
    }
}

これでソーシャルログイン認証の準備が整いました。

ソーシャルログイン認証処理を追記

通常のログインコントローラーソーシャルログイン認証処理を付け加えます。

/app/Http/Controllers/LoginController.php

/**
 * redirect to oauth page
 *
 * @return IlluminateHttpResponse
 */
public function redirectToProvider($provider)
{
    return Socialite::driver($provider)->redirect();
}

/**
 * get user info from oauth
 *
 * @return IlluminateHttpResponse
 */
public function handleProviderCallback($provider)
{
    try {
        $user = Socialite::driver($provider)->user();
        $account = SocialAccount::firstOrCreate([
            'provider'    => $provider,
            'provider_id' => $user->getId(),
        ]);
        if (empty($account->user)) {
            $user = User::create([
                'name'   => $user->getName(),
                'email'  => $user->getEmail()
            ]);
            $account->user()->associate($user);
        }
        $account->save();
        Auth::login($account->user, true);
    } catch (Exception $e) {
        return redirect('/login');
    }
    return redirect($this->redirectTo);
}

[redirectToProvider($provider)]で各SNSログイン認証画面へリダイレクトさせ、[handleProviderCallback($provider)]で帰ってきた値を利用して登録orログインを行います。

/routes/web.php

最後にルートを追加して完了です。

Route::get('login/{provider}', 'AuthLoginController@redirectToProvider');
Route::get('login/{provider}/callback', 'AuthLoginController@handleProviderCallback');

{provider}に”google“や”facebook“が入ります。リンクはこんな感じ。

<a href="{{ url('login/facebook') }}" class="btn btn-primary"><i class="fa fa-facebook"></i> Facebook でログインする</a>
<a href="{{ url('login/google') }}" class="btn btn-danger"><i class="fa fa-google-plus"></i> Google+ でログインする</a>

モバイルバージョンを終了