6/21 13:22 最終更新完了です。
Laravelの認証の仕組みを利用することは、公式ドキュメントや色々な記事を読むことで可能になりましたが、
「じゃあ実際どういう仕組みで認証してるんだろう」という疑問にぶち当たり、調べて見ました。
Laravelのmiddleware authを理解したい
こちらの記事のLaravel5.5版です。構成も丸パクリさせていただいています。
環境
Laravel 5.5
PHP 7.0
MacOSX 10.13
調査
php artisan make:auth
で自動生成されたコードによれば、認証が必要なものはMiddlewareで定義する。
class HomeController extends Controller
{
//コンストラクタ
public function __construct()
{
$this->middleware('auth');
}
・Http/Kernel.phpにて「auth」というaliasを登録している
Http/Kernel.php
protected $routeMiddleware = [
'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
※ 5.5〜 Framework内のクラスを利用するように変更された(らしい)
\Illuminate\Auth\Middleware\Authenticate でやっていること
- handleが定義されている(自明ですかね)
-
ガードを指定することで、認証の方式を変更できる
- $guards に指定された文字列が入る(
$this->middleware('auth:web,api');
のように複数指定が可能なので配列)
- $guards に指定された文字列が入る(
- $guardsが指定されていないときは、\Illuminate\Auth\AuthManager\authenticate() を呼ぶ → 本資料はこちらについてだけ理解を進める
- 実装は
interface Illuminate\Contracts\Auth\Factory
だが、実際にDIコンテナに登録されているのは上のクラス(\Illuminate\Foundation\Application\registerCoreContainerAliases())
- 実装は
\Illuminate\Auth\AuthManager\authenticate() が呼ばれるまで
- \Illuminate\Auth\AuthManager\authenticate() はコード上存在しないです。
\Illuminate\Auth\AuthManager.php
public function __call($method, $parameters)
{
return $this->guard()->{$method}(...$parameters);
}
$this->guard() でオブジェクトが特定されるまで
Illuminate\Auth\AuthManager.php
public function guard($name = null)
{
$name = $name ?: $this->getDefaultDriver();
return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name);
}
- $this->resolve() で解決している模様
- $nameは、"web"(デフォルト: auth.default.web)
Illuminate\Auth\AuthManager.php
protected function resolve($name)
{
$config = $this->getConfig($name);
if (is_null($config)) {
throw new InvalidArgumentException("Auth guard [{$name}] is not defined.");
}
if (isset($this->customCreators[$config['driver']])) {
return $this->callCustomCreator($name, $config);
}
$driverMethod = 'create'.ucfirst($config['driver']).'Driver';
if (method_exists($this, $driverMethod)) {
return $this->{$driverMethod}($name, $config);
}
throw new InvalidArgumentException("Auth guard driver [{$name}] is not defined.");
}
- $config['driver'] は、config/auth.php で定義しているdriverが読み込まれる。
- デフォルトのままだと'session'
-
$driverMethod = 'createSessionDriver'
で話を進める
Illuminate\Auth\AuthManager.php
public function createSessionDriver($name, $config)
{
$provider = $this->createUserProvider($config['provider'] ?? null);
$guard = new SessionGuard($name, $provider, $this->app['session.store']);
// When using the remember me functionality of the authentication services we
// will need to be set the encryption instance of the guard, which allows
// secure, encrypted cookie values to get generated for those cookies.
if (method_exists($guard, 'setCookieJar')) {
$guard->setCookieJar($this->app['cookie']);
}
if (method_exists($guard, 'setDispatcher')) {
$guard->setDispatcher($this->app['events']);
}
if (method_exists($guard, 'setRequest')) {
$guard->setRequest($this->app->refresh('request', $guard, 'setRequest'));
}
return $guard;
}
- SessionGuard が、guardクラス
createUserProviderでやっていること
↓ 5.2解説より (同じ模様)
- configのauth.providers.{$provider}の値 → auth.providers.usersの値を取得する
- デフォルト:auth.providers.users = ['driver'=>'eloquent','model'=>'App\User']
- 「何を使って、どこからUser情報を取得するか」というのを取得する。
- デフォルトでは、「eloquentを使って、App\Userモデルの情報をとる」ということ
本稿の追記
- Laravelで用意されているUserProviderは以下
- auth.providers.users.driver = 'eloquent'の場合は、Illuminate\Auth\EloquentUserProvider
- 'database'の場合は、Illuminate\Auth\DatabaseUserProvider
- UserProviderの主なメソッドは以下
- retrieveById():IDで認証する
- retrieveByToken():token(remember me)で認証する
- updateRememberToken():token(remember me)を更新する
- retrieveByCredentials():credentialを更新する
- validateCredentials():credentialを利用してユーザを検証する
new SessionGuard()でやっていること
Illuminate\Auth\SessionGuard.php
public function __construct($name,
UserProvider $provider,
Session $session,
Request $request = null)
{
$this->name = $name;
$this->session = $session;
$this->request = $request;
$this->provider = $provider;
}
- セッションやリクエストのセットを行っている
- 5.2と同じ模様
SessionGuard::authenticate() でやっていること
- authenticate() メソッドは Illuminate\Auth\GuardHelper に存在(use で読み込まれている)
GuardHelper.php
public function authenticate()
{
if (! is_null($user = $this->user())) {
return $user;
}
throw new AuthenticationException;
}
user() がやっていること
- GuardHelperの$this->userは、SessionGuard に実装されている(戻った)
- $this->loggedOut = true だったらnullを返す
- logout() で trueがセットされる。ログアウトしたけどSessionが残っているのを防ぐ模様
- $this->user が存在していれば、それを返す
- DBアクセスを減らす目的
- これに該当することってあるんですかね?
- SessionからIDを取得
- Sessionについては別記事でまとめる
$id = $this->session->get($this->getName());
- IDが取れたら、UserProviderのretriveByIdで、Userオブジェクトを取得する
- 取得できたら認証完了のイベント通知を行う
-
$recaller = $this->recaller()
で、Recallerオブジェクト生成- "remember me" Cookieの情報を保持する
- 情報がない場合はnull
- ここまでで
$this->user
がとれていなくて、$recaller
が存在している場合、Recallerから$this->user
の取得を試みる - 最後にログインユーザが取れていれば
$this->user
、取れていなければnull(ログインなし)を返す
以上です。