- LaravelではfacebookやtwitterのOAuth認証によるログイン機能を実現するためのパッケージ「laravel/socialite」が存在する。
- 日本国内向けのサービス(LINEやYahoo!JAPAN)を使った認証はサポートされていないが、これについてはこちらのポストで。
追記
- 2017.05.19
SocialController::createOrGetUser()において、各種サービスから取得したメールアドレスを保存していたが、make:authを使って作成する認証方式を併用する場合に、SNS登録メールアドレスとバッティングしてログインできなくなる事象があったため、該当箇所をコメントアウトしました。
前提
-
php artisan make:authを実行済みであること
導入手順
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>
...