LaravelのSocialiteとPassportを使ってWeb APIの認証機能を実装した話

LaravelのSocialiteとPassportを使ってWeb APIの認証機能を実装した話

現在開発中のアプリで、LaravelのSocialiteとPassportを使って認証機能を実装したので、その内容をまとめておきます。

設計

シーケンス

アプリも踏まえた全体のシーケンスは下図の通りです。(認可サーバ=Facebook等のサーバと捉えてください。)

アクセストークンが2種類出てきますが、それぞれの役割は下記の通りです。

  • アクセストークン(SNS):認可サーバから取得する有効期限の長いトークンです。今回はリフレッシュトークン(アクセストークンを再発行する際に必要なトークン)として使用します。
  • アクセストークン(Passport):クライアント⇆APIサーバでの認証に使用する有効期限の短いトークンです。上記のSNSトークンの妥当性確認後、APIサーバで発行します。

今回は、サーバ側の処理についてのみ触れるため④と⑥の実装方法について記載します。④ではLaravelのSocialite(ソーシャルログインを簡単に実装するための機能)、⑥ではLaravelのPassport(API認証を簡単に実装するための機能)を使います。

なぜソーシャルログインを使うのか?

ソーシャルログインを使用せず、独自の認証機能を実装しても良いのですが、ユーザにとって以下3つのメリットがあると考えています。

  • 信頼性がそこまで高くないアプリにパスワードなどを登録せずに済む。
  • 氏名や居住地などの基本情報を流用できる。(アプリケーションの設定次第ですが)
  • SNSにログイン済みであれば、ログイン情報(メールやパスワード等)の入力等が不要。

Socialite

設定

ドキュメントに記載してある通りですが、一応。
【Socialiteのインストール】

composer require laravel/socialite

【.env】
Client IDやClient SecretをFacebook等のDeveloperページから取得し、以下のように設定します。(事前にアプリの登録が必要。)

FB_CLIENT_ID="FacebookのClient ID"
FB_CLIENT_SECRET="FacebookのClient Secret"

【config/services.php】

'facebook' => [
'client_id' => env('FACEBOOK_CLIENT_ID'), // FacebookのClient ID
'client_secret' => env('FACEBOOK_CLIENT_SECRET'), // FacebookのClient Secret
],

機能実装

【LoginController.php】
クライアントから送られたトークンが妥当であれば、下記を記載するだけでFacebookに登録されているユーザ情報を取得できます。

$socialUser = Socialite::driver('facebook')->userFromToken('アプリから送られたトークン');
// $socialUser-> とすればFacebookで登録している名前を取得できる

Passport

設定

こちらも、ドキュメントに記載してある通りです。
【Passportのインストール】

composer require laravel/passport
php artisan migrate
php artisan passport:install

【AuthServiceProvider】
アクセストークンの管理のルートを登録します。

public function boot()
{
$this->registerPolicies();
//以下を追記
Passport::routes();
}

【config/auth.php】
api認証のdriverオプションをpassportへ変更します。

'guards' => [
'api' => [
'driver' => 'passport', // token→passportへ変更
'provider' => 'users',
],
],

機能実装

【LoginController.php】
Passportで発行できるアクセストークンにはいくつか種類がありますが、今回はパーソナルアクセストークンを使います。
以下では、Facebookから取得した名前を持つユーザのインスタンスを生成しそのユーザに対してトークンを発行しています。

// ユーザの作成
$user = App\User::create(['name' => $socialUser->name]);
// パーソナルアクセストークンの発行
$token = $user->createToken('hilcra')->accessToken

あとは、この結果をクライアントに返して、リクエスト時にこのトークンをヘッダーにくっつけて送ってもらいます。(ここでは、詳細の説明は省きます。)

パーソナルアクセストークンの有効期限設定

これで、一通りの機能実装が完了し、あとはトークンの有効期限を設定するだけだと思っていると、ドキュメントに以下の記載が見つかりました。

パーソナルアクセストークンを使用した場合、有効期限は設定できないとのこと。
ただ、いろいろ調べて思考錯誤していると、無事設定することができました。以下、ご参考までに。
結論から言うと、PassportServiceProviderクラスのregisterAuthorizationServerというメソッドをオーバーライドすると有効期限を設定可能です。

【App/Providers/HogePassportServiceProvider.php】※各自クラスを作成ください

class HogePassportServiceProvider extends PassportServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
parent::boot();
}
/**
* Register the application services.
*
* @return void
*/
public function register()
{
parent::register();
}
/**
* Register the authorization server.
*
* @return void
*/
protected function registerAuthorizationServer()
{
$this->app->singleton(AuthorizationServer::class, function () {
return tap($this->makeAuthorizationServer(), function ($server) {
$server->enableGrantType(
$this->makeAuthCodeGrant(), Passport::tokensExpireIn()
);
$server->enableGrantType(
$this->makeRefreshTokenGrant(), Passport::tokensExpireIn()
);
$server->enableGrantType(
$this->makePasswordGrant(), Passport::tokensExpireIn()
);
// ★以下で設定
$server->enableGrantType(
new PersonalAccessGrant, new DateInterval('PT30M')
);
$server->enableGrantType(
new ClientCredentialsGrant, Passport::tokensExpireIn()
);
if (Passport::$implicitGrantEnabled) {
$server->enableGrantType(
$this->makeImplicitGrant(), Passport::tokensExpireIn()
);
}
});
});
}
}

プロバイダを新規で作成したので、config/app.phpへの追加も忘れずに。
【config/app.php】

'providers' => [
App\Providers\HogePassportServiceProvider::class,
]