menu-icon

Laravel Socialiteでソーシャルログイン

ソーシャルログインを導入すれば、ソーシャルメディアに登録されている情報を使ってログインや会員登録を行うことができ、ユーザーの利便性が向上します。LaravelではLaravel Socialiteを使うことで、簡単にソーシャルログインを導入できます。実際に実装してみたので、導入メモを残しておきます。なおソースはこちらにあります。

サンプルの仕様

  • ソーシャルプロパイダはLINEとTwitter
  • ユーザーの識別は提供されるIDを使用(メールアドレスは使わない)

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

以下のコマンドでLaravel Socialiteをインストールします。

$ composer require laravel/socialite

これで以下のサービスのソーシャルログインを利用できるようになります。

  • Facebook
  • Twitter
  • LinkedIn
  • Google
  • Github
  • Gitlab
  • Bitbucket

上記以外を利用する場合、Socialite Providersでプロバイダを調べて、別途インストールする必要があります。今回はLINEを使用するのでLINE用プロバイダをインストールします。

$ composer require socialiteproviders/line

コンフィグ

Socialite用のコンフィグ設定です。config/services.phpに以下を追加します。

config/services.php
    'line' => [
        'client_id'     => env('LINE_CLIENT_ID'),
        'client_secret' => env('LINE_CLIENT_SECRET'),
        'redirect'      => '/login/line/callback',
    ],

    'twitter' => [
        'client_id'     => env('TWITTER_CLIENT_ID'),
        'client_secret' => env('TWITTER_CLIENT_SECRET'),
        'redirect'      => '/login/twitter/callback',
    ],

そして.envに以下の環境変数を追加します(値は各サービスにて取得したものです)。

.env
TWITTER_CLIENT_ID=xxxxxxxxx
TWITTER_CLIENT_SECRET=xxxxxxxxx

LINE_CLIENT_ID=xxxxxxxxx
LINE_CLIENT_SECRET=xxxxxxxxx

拡張(追加のプロバイダを利用する場合)

LINEのように追加のプロバイダを利用する場合、以下の拡張が必要になります。以下はLINEの場合ですが、手法はその他のプロバイダでも同一です。

config/app.php
'providers' => [

    // other providers

    SocialiteProviders\Manager\ServiceProvider::class, // add
];
app/Providers/EventServiceProvider.php
protected $listen = [

    // other listeners

    \SocialiteProviders\Manager\SocialiteWasCalled::class => [
        'SocialiteProviders\\Line\\LineExtendSocialite@handle',
    ],
];

これでSocialiteを使用するための準備は完了です。

実装

実際に実装してみます。

Users テーブル定義

デフォルトのものを変更して使います。

<?php

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

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->string('name');
            $table->enum('provider', ['line', 'twitter']);
            $table->string('provided_user_id');
            $table->timestamps();

            $table->unique(['provider', 'provided_user_id']);
        });
    }

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

User モデル

これもテーブル定義に合わせて変更します。Illuminate\Contracts\Auth\Authenticatableを実装する必要があります。

app/User.php
<?php

namespace App;

use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;
use Illuminate\Auth\Authenticatable;

class User extends Model implements AuthenticatableContract
{
    use Authenticatable, Notifiable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'provider', 'provided_user_id',
    ];

    /**
     * Get the password for the user.
     *
     * @return string
     */
    public function getAuthPassword()
    {
        // We don't use password login.
        return '';
    }

    /**
     * Get the column name for the "remember me" token.
     *
     * @return string
     */
    public function getRememberTokenName()
    {
        // We don't use this.
        return '';
    }
}

コントローラー

以下の3つのアクションを用意しました。

  • 各サービスのログイン画面へリダイレクト
  • 各サービスからの戻り先(ユーザー登録 and ログイン)
  • ログアウト
app/Http/Controllers/Auth/LoginController.php
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;

class LoginController extends Controller
{
    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    /**
     * Redirect the user to the provider authentication page.
     *
     * @param string $provider
     * @return \Illuminate\Http\Response
     */
    public function redirectToProvider($provider)
    {
        return Socialite::driver($provider)->redirect();
    }

    /**
     * Obtain the user information from the provider.
     *
     * @param string $provider
     * @return \Illuminate\Http\Response
     */
    public function handleProviderCallback($provider)
    {
        $provided_user = Socialite::driver($provider)->user();

        $user = User::where('provider', $provider)
            ->where('provided_user_id', $provided_user->id)
            ->first();

        if ($user === null) {
            // redirect confirm
            $user = User::create([
               'name'               => $provided_user->name,
               'provider'           => $provider,
               'provided_user_id'   => $provided_user->id,
            ]);
        }

        Auth::login($user);

        return redirect()->route('index');
    }

    /**
     * Log the user out of the application.
     *
     * @return \Illuminate\Http\Response
     */
    public function logout()
    {
        Auth::logout();

        return redirect()->route('index');
    }
}

ルーティング

ルーティングは以下のようにしました。各サービスからの戻り先はコンフィグで指定したものと一致するようにします。

routes/web.php
<?php

Route::view('/', 'index')->name('index');
Route::get('/login/{provider}', 'Auth\LoginController@redirectToProvider')->name('login');
Route::get('/login/{provider}/callback', 'Auth\LoginController@handleProviderCallback');
Route::get('/logout', 'Auth\LoginController@logout')->name('logout');

フロントまわり

特筆すべきことはありません。ソースはこちらにあります(CSSフレームワークのBulmaを使用しています)。

動作確認

表示を確認します。

未ログイン状態

各ログインボタンを押すと、各サービスのログイン画面へ遷移します。

LINE ログイン画面
Twitter ログイン画面

各サービスでログインすると、ユーザーが追加されます。

mysql> select id, name, provider from users;
+----+------+----------+
| id | name | provider |
+----+------+----------+
|  1 | hoge | line     |
|  2 | hoge | twitter  |
+----+------+----------+
2 rows in set (0.00 sec)

まとめ

Laravel Socialiteを使ってソーシャルログインを導入してみました。複数のサービスを扱う場合でも、個別に実装しなくて良いので非常に楽でした。提供されているプロバイダも豊富なので、メジャーなサービスであれば、サクッと導入できると思います。