LoginSignup
31
23

More than 3 years have passed since last update.

Laravelのmiddleware authを理解したい(6.x)

Posted at

以前書いた、Laravelのmiddleware authを理解したい (5.5)から、約2年経過しましたが、LTSも新バージョンが出ているので、差分を理解するという意味も含めて6.xについて調べてみることにしました。

例によって、Laravelのmiddleware authを理解したい と同じ構成です(感謝です!)

環境

Laravel 6.18.6 (laravel/framework のSHA: 4ef5f9612c2694c915f53f0cec3e4081e9bfc778)

調査


make:auth artisanコマンドがなくなりました!

マニュアルより、

composer require laravel/ui "^1.0" --dev

php artisan ui vue --auth

とやることで、vue.jsを利用したスカルフォードが生成される。


自動生成コードによれば、認証が必要なものはMiddlewareで定義する。

Http/Controllers/HomeController.php
class HomeController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }
  • Http/Kernel.php にて、「auth」というaliasを登録している。
Http/Kernel.php
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,

\Illuminate\Auth\Middleware\Authenticate でやっていること

\Illuminate\Auth\Middleware\Authenticate.php
    public function handle($request, Closure $next, ...$guards)
    {
        $this->authenticate($request, $guards);

        return $next($request);
    }
  • 上記の$guards に、指定された文字列が入る($this->middleware('auth:web.api'); のように複数指定が可能なので可変引数
  • Illuminate/Auth/AuthManagerで処理を行う
    • interafce Illuminate\Contracts\Auth\Factory が、DIされているが、下記の通り実態はAuthManager
\Illuminate\Auth\Middleware\Authenticate.php
// use Illuminate\Contracts\Auth\Factory as Auth; とされている
    /**
     * Create a new middleware instance.
     *
     * @param  \Illuminate\Contracts\Auth\Factory  $auth
     * @return void
     */
    public function __construct(Auth $auth)
    {
        $this->auth = $auth;
    }
/Illuminate/Foundation/Application.php
    public function registerCoreContainerAliases()
    {
        foreach ([
            'app'                  => [self::class, \Illuminate\Contracts\Container\Container::class, \Illuminate\Contracts\Foundation\Application::class, \Psr\Container\ContainerInterface::class],
            'auth'                 => [\Illuminate\Auth\AuthManager::class, \Illuminate\Contracts\Auth\Factory::class],
  • $guardで指定された分だけ、Guardを使用して、認証済みか確認(/Illuminate/Auth/SessionGuard::check())し、認証済みのGuardの使用を宣言する
    • ここで、config/auth.php で指定がなかったguardsは、Exceptionが発生する
    • 指定可能なdriverは、「session」「token」とのことだが、ここでは省略
    • $guardを指定していない場合は、nullとして処理され、AuthManagerで、config/auth.phpの、defaultsが指定される。初期設定ではweb → 本資料では、このパターンについて理解を進める

/Illuminate/Auth/SessionGuard::check() が呼ばれるまで

呼んでいる箇所

/Illuminate/Auth/Middleware/Authenticate.php
    protected function authenticate($request, array $guards)
    {
        if (empty($guards)) {
            $guards = [null];
        }

        foreach ($guards as $guard) {
            if ($this->auth->guard($guard)->check()) {
                return $this->auth->shouldUse($guard);
            }
        }

$this->auth->guard() でオブジェクトが特定されるまで

/Illuminate/Auth/AuthManager.php
    public function guard($name = null)
    {
        $name = $name ?: $this->getDefaultDriver();

        return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name);
    }
  • 今回は$name = nullのため、$name = 'session' として処理
/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 driver [{$config['driver']}] for guard [{$name}] is not defined."
        );
    }
  • AuthManage.php::resolve() で、使用するGuardを決定

AuthManager::createSessionDriver() で、Guardが生成される

/Illuminate/Auth/AuthManager.php
    /**
     * Create a session based authentication guard.
     *
     * @param  string  $name
     * @param  array  $config
     * @return \Illuminate\Auth\SessionGuard
     */
    public function createSessionDriver($name, $config)
    {
        $provider = $this->createUserProvider($config['provider'] ?? null);

        $guard = new SessionGuard($name, $provider, $this->app['session.store']);
  • 実体は/Illuminate/Auth/SessionGuard

AuthManager::createUserDriver() でやっていること

(実装は、trait /Illuminate/Auth/CreateUserProviders

5.2解説より、

  • config/auth.phpの、auth.providers.{$provider} の値 → auth.providers.usersの値を取得する
    • デフォルト:auth.providers.users = ['driver'=>'eloquent','model'=>'App\User']
  • 「何を使って、どこからUser情報を取得するか」というのを取得する。
  • デフォルトでは、「eloquentを使って、App\Userモデルの情報をとる」ということ
  • Laravelでは、driverに以下の設定が可能
    • eloquent
      • Eloquent Modelを使ってユーザを特定
      • modelで、どのModelを使用するか指定
      • Illuminate\Auth\EloquentUserProvider を使う
    • database
      • データベースを使う
      • tableでテーブル名を指定
      • Illuminate\Auth\DatabaseUserProvider を使う
  • interface Illuminate\Contracts\Auth\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::check() でやっていること

trait \Illuminate\Auth\GuardHelpersに実装

    /**
     * Determine if the current user is authenticated.
     *
     * @return bool
     */
    public function check()
    {
        return ! is_null($this->user());
    }
  • user() を使って、認証されているかを返す

SessionGuard::user() の処理


フレームワークの根幹に関わるところなので、基本的な処理は変わっていない印象です。(メソッド名とかクラス名が少し変わってるけど、流れは変わっていない)
参考になればと思います。

31
23
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
31
23