PHP
laravel5.5

Laravelのmiddleware authを理解したい (5.5)

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が指定されていないときは、\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;
}


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(ログインなし)を返す


以上です。