こんにちは!むちょこです。
今日はリクエストでいただいたsocialiteを使ったOAuth認証の実装方法について書いてみようと思います☆
既にたくさんの類似記事があるのですが、私の周りには「読んでもよくわからなかった…」という方がたくさんいたので
その方々の疑問にできる限り丁寧に答える形で書きました。たぶんこれ以上丁寧な記事はないと思います……!
その代わりかなり長いので、不要なところはどんどん飛ばして読んでくださいね。
1. 前提条件
環境
Laravel Framework 5.7.13
要件
- 通常のパスワード認証と共存する。
- 認証方法に関わらず、メールアドレスが一致すれば同一人物とみなす。
- メールアドレス情報は必須とする。
- SNSの情報を認証以外には使用しない。
- 今回の対象プロバイダはTwitterのみだが、今後Facebookなど他のプロバイダを追加する可能性がある。
実装済みの機能
以下のコマンドで通常のパスワード認証機能は実装済みのものとします。
$ php artisan make:auth
$ php artisan migrate
詳しく知りたい方は、以前の記事のartisanコマンドで基本機能をサクッと生成をご覧ください 。
Laravelでサクッとログイン機能を実装する方法2. OAuth認証の流れ
「そもそもOAuth認証ってよくわかんない。どういう動きしてるの?」という方向けに、全体の処理の流れをフローチャート風にして書きました。
実際にOAuth認証と呼ばれるのは③④の部分で、他の部分は一般的にOAuth認証に付随する処理です。今回もこの流れで実装していきます。
3. Socialiteのインストール
それでは実装していきましょう。
まずはベースとなるSocialiteパッケージのインストールです。
方法はたった一行のコマンドを実行するだけ。
$ composer require laravel/socialite
4. Twitter API Keyの取得
今回はTwitterのソーシャルログインを実装するため、TwitterのAPI Keyが必要です。
Twitterの場合はまず、こちらのURLからアプリケーションの新規作成を行います。
https://developer.twitter.com/en/apps
入力時のポイント
アプリケーションの作成の際に、気を付けてほしいポイントが3つあります。
1)Enable Sign in with Twitterにチェックを入れる
→OAuth機能を使うために必要です。
2)Callback URLsに認証結果を受け取るURLを記入する
→フローチャートの④を行うURLです。
3)Terms of Service URL, Privary policy URLにそれぞれ利用規約とプライバシーポリシーのURLを入力する
→メールアドレスを取得するために必要です。
権限の編集
アプリケーションの作成ができたら、Permissionsタブを開いてEditを押し、メールアドレス情報をリクエストしましょう。
これでTwitterのアプリケーション登録は完了です。
5. API Keyの設定
.envファイルを開き、API Keyやコールバックのパスを設定していきます。
コールバックのパスは、 フローチャートの④にあたるURLで、TwitterのCallBackURLsにも入力したものです。書き方は絶対パスor相対パスどちらでも構いません。
API Keyは、TwitterアプリページのKeys and tokensタブに記載してあります。
TWITTER_CLIENT_ID=(API Key)
TWITTER_CLIENT_SECRET=(API secret key)
TWITTER_CLIENT_CALLBACK=/login/twitter/callback
.envファイルに値が書けたら、config/services.phpでそれを使うよう指定します。
'twitter' => [
'client_id' => env('TWITTER_CLIENT_ID'),
'client_secret' => env('TWITTER_CLIENT_SECRET'),
'redirect' => env('TWITTER_CLIENT_CALLBACK')
],
Twitter以外のプロバイダを利用する場合は、.envとconfig/services.phpに同様に記載するだけでOKです。
この後のプログラム部分に変更や追記の必要はありません。
6. リダイレクト処理
自分のサイトのとあるページにアクセスしたら、プロバイダの認証画面にリダイレクトする処理を書きます。
よくあるのがこんな感じのボタンのリンク先です。
フローチャートでいうと②の部分です。
Route::get('/login/{provider}', 'Auth\LoginController@redirectToProvider');
use Socialite;
class LoginController extends Controller
{
/**
* OAuth認証先にリダイレクト
*
* @param str $provider
* @return \Illuminate\Http\Response
*/
public function redirectToProvider($provider)
{
return Socialite::driver($provider)->redirect();
}
}
redirectToProviderメソッドの引数$providerには、/login/{provider}の{provider}部分の文字列が渡され、各プロバイダの認証ページにリダイレクトされます。
今回の場合は
/login/twitterにアクセスするとTwitterの認証ページにリダイレクトされるので、このようなページ(Twitterに未ログインの場合はログインフォーム)が表示されるはずです。
7. 認証結果の受け取り
プロバイダの認証が済むと、コールバックに指定したURL宛に認証結果が渡されます。
受け取るための準備をしていきましょう。フローチャートの④にあたる部分です。
Route::get('login/{provider}/callback', 'Auth\LoginController@handleProviderCallback');
TwitterのCallback URLsや.envに/login/twitter/callbackを設定したので、それに対応するようルーティングに書きます。
“twitter”部分はリダイレクトのときと同様に、他のプロバイダも使えるよう変数にしておきます。
class LoginController extends Controller
{
/**
* OAuth認証の結果受け取り
*
* @param str $provider
* @return \Illuminate\Http\Response
*/
public function handleProviderCallback($provider)
{
try {
$providerUser = \Socialite::with($provider)->user();
} catch(\Exception $e) {
return redirect('/login')->with('oauth_error', '予期せぬエラーが発生しました');
}
}
}
プロバイダから送られたユーザ情報は、\Socialite::with($provider)->user();で取得することができます。
無効なトークンが使われるなどの予期せぬエラーが起こる可能性があるので、ここは例外処理を使うのがオススメです☆
リダイレクト先でwithメソッドのフラッシュメッセージを表示するためには、対応するbladeファイルに以下のように書きます。
@if (session('oauth_error'))
{{ session('oauth_error') }}
@endif
8. ユーザ登録とログイン処理
そろそろ完成が見えてきましたね。
フローチャート⑥⑦部分を実装していきましょう。
まずはDBの調整です。
$ php artisan make:migration change_users_table
OAuthで新規登録するユーザにはパスワード情報がないので、passwordカラムをnullableにします。
class ChangeUsersTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('users', function (Blueprint $table) {
//passwordカラムにnullを許可
$table->string('password')->nullable()->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('users', function (Blueprint $table) {
$table->string('password')->nullable(false)->change();
});
}
}
doctrine/dbalをインストールしてから、マイグレーションを実行します。
$ composer require doctrine/dbal
$ php artisan migrate
doctrine/dbalはカラムの変更に必要なライブラリです。
もし既に追加済みでしたらマイグレーションの実行のみ行ってください。
DBの準備ができたら、ロジックを書いていきます。
メールアドレスが既に登録されている場合はログイン、
未登録の場合はユーザ名と共に登録してからログインを行う処理を書きます。
use Illuminate\Support\Facades\Auth;
use App\User;
class LoginController extends Controller
{
/**
* OAuth認証の結果受け取り
*
* @param str $provider
* @return \Illuminate\Http\Response
*/
public function handleProviderCallback($provider)
{
try {
$providerUser = \Socialite::with($provider)->user();
} catch(\Exception $e) {
return redirect('/login')->with('oauth_error', '予期せぬエラーが発生しました');
}
if ($email = $providerUser->getEmail()) {
Auth::login(User::firstOrCreate([
'email' => $email
], [
'name' => $providerUser->getName()
]));
return redirect($this->redirectTo);
} else {
return redirect('/login')->with('oauth_error', 'メールアドレスが取得できませんでした');
}
}
}
firstOrCreateメソッドはLaravel側が用意しているメソッドで、第一引数で検索し、結果が空なら第二引数の値を加えて作成してから返してくれるという便利メソッドです。
Auth::login()でログインさせたら、LoginControllerクラスのメンバ変数$redirectToにリダイレクトさせています。
これでsocialiteを使ったログイン機能の実装は終わりです。
お疲れ様でした!
[…] → Socialiteの使い方を世界一丁寧に解説した […]
[…] 今回は、以前書いたSocialite導入の記事を基にしたテストコード例をご紹介してみようと思います。 […]