Skip to main content

Laravel: 認証のカスタマイズ

標準のデータベース以外のソースで認証をおこなうため、カスタマイズする。

参考) https://laravel.com/docs/6.x/authentication#adding-custom-guards

環境

  • Laravel 6

概要

以下のインタフェースを実装したクラスを作成する。

InterfacePurpose
GuardIlluminate\Contracts\Auth\Guard認証要求を処理し、認証結果を保持管理する。
ProviderIlluminate\Contracts\Auth\UserProvider認証情報から User のインスタンスを返す。
UserIlluminate\Contracts\Auth\Authenticatable認証情報を持っているクラス。

どの実装を使用するかは、config/auth.php に設定する。

// config/auth.php
return [
...
'guards' => [
'web' => [
'driver' => 'session', ★使用する Guard の名前
'provider' => 'users', ★↓に定義した providers の名前
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
'providers' => [
'users' => [
'driver' => 'eloquent', ★使用する Provider の名前
'model' => App\User::class, ★と、パラメタ
],
],
...
];

標準で用意されている Guard

driver の名前実装備考
requestIlluminate\Auth\RequestGuard
sessionIlluminate\Auth\SessionGuard認証結果をセッションに保持する。
tokenIlluminate\Auth\TokenGuard

標準で用意されている Provider

driver の名前実装備考
databaseIlluminate\Auth\DatabaseUserProviderDB による認証。
eloquentIlluminate\Auth\EloquentUserProviderEloquent 経由 DB による認証。User の Eloquent モデルには Illuminate/Auth/Authenticatable トレイトを use するだけで実装完了。

ログインシーケンス

ログインユーザーの取得

実装

参考) Adding Custom User Providers - Laravel

ユーザープロバイダクラスを作成

UserProvider インタフェースを実装した、ユーザーを提供するプロバイダクラスを作成する。実装する関数は以下の通り。

MethodDescription
retrieveByIdID からユーザーインスタンスを生成する。
retrieveByTokenID と Remember Token からユーザーインスタンスを取得する。ログイン時に「Remember me」をチェックし、ログインセッション切れ後に自動再ログインするときに使用する。「Remember me」機能を実装しない場合は使用されない。
updateRememberToken「Remeber me」をチェックしてログインした際に呼ばれるので、Remember Token を保存する。「Remember me」機能を実装しない場合は使用されない。
retrieveByCredentialsログイン時に入力された認証情報(ユーザー名、パスワード等)からユーザーインスタンスを生成する。パスワードを含む認証情報が渡ってくるが、ここで認証はしないこと。
validateCredentials取得したユーザーインスタンスと入力された認証情報をもとに、ここで認証をおこなう。

実際のデータソースへのアクセスをおこなう MyUserRepository クラスが存在する場合の例。(「Remeber me」機能の実装は省略した。)

<?php
namespace App\Providers;

use App\Model\MyUserRepositoryInterface;

class MyUserProvider implements UserProvider
{
protected $userReposotiry;

public function __construct(MyUserRepositoryInterface $userReposotiry)
{
$this->userReposotiry = $userReposotiry;
}

public function retrieveById($identifier): ?Authenticatable
{
return $this->userReposotiry->getUserById($identifier);
}

public function retrieveByToken($identifier, $token): ?Authenticatable
{
throw new Exception(sprintf('Not implemented: %s->%s()', self::class, __FUNCTION__));
}

public function updateRememberToken(Authenticatable $user, $token): void
{
throw new Exception(sprintf('Not implemented: %s->%s()', self::class, __FUNCTION__));
}

public function retrieveByCredentials(array $credentials): ?Authenticatable
{
if (!isset($credentials['email'])) {
return null;
}
return $this->userReposotiry->getUserByLogin($credentials['email']);
}

public function validateCredentials(Authenticatable $user, array $credentials): bool
{
if (!isset($credentials['email']) || !isset($credentials['password'])) {
return false;
}
return $this->userReposotiry->authenticateUser($credentials['email'], $credentials['password']);
}
}

作成したユーザープロバイダクラスを登録

<?php
namespace App\Providers;

use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;

class AuthServiceProvider extends ServiceProvider
{
public function boot()
{
...
Auth::provider('my_user', function ($app, array $config) {
return $app->make(MyUserProvider::class);
});
}
}

作成したユーザープロバイダクラスを設定

config/auth.php の provider に追加し、guards から指定する。

'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'my_users',
],
],

'providers' => [
'my_users' => [
'driver' => 'my_user',
],
],

ユーザークラスを作成

プロバイダが返すユーザーインスタンスは、Authenticatable インタフェースを実装する必要がある。

MethodDescription
getAuthIdentifierNameユーザーのプライマリキー名を返す。(例: "id")
getAuthIdentifierユーザーのプライマリキーを返す。
getAuthPasswordユーザーのハッシュ化されたパスワードを返す。「Remember me」機能を実装しない場合は使用されない。
getRememberTokenユーザーの Remember Token を返す。「Remember me」機能を実装しない場合は使用されない。
setRememberTokenユーザーの Remember Token を設定する。「Remember me」機能を実装しない場合は使用されない。
getRememberTokenNameユーザーの Remember Token 名を返す。「Remember me」機能を実装しない場合は使用されない。
namespace App\Model;

use Exception;
use Illuminate\Contracts\Auth\Authenticatable;

/**
* MyUser model
*/
class MyUser implements Authenticatable
{
public function getAuthIdentifierName()
{
return 'id';
}

public function getAuthIdentifier()
{
return $this->getId();
}

public function getAuthPassword(): string
{
throw new Exception(sprintf('Not implemented: %s->%s()', self::class, __FUNCTION__));
}

public function getRememberToken(): string
{
throw new Exception(sprintf('Not implemented: %s->%s()', self::class, __FUNCTION__));
}

public function setRememberToken($value): void
{
throw new Exception(sprintf('Not implemented: %s->%s()', self::class, __FUNCTION__));
}

public function getRememberTokenName(): string
{
throw new Exception(sprintf('Not implemented: %s->%s()', self::class, __FUNCTION__));
}
}