LaravelのAuth::guardについて書いてみた


◆前回までの記事

前回までの学習でサービスプロバイダを使って、サービスコンテナにバインド(登録)する方法とFacadeがサービスコンテナにバインド(登録)した名前と違う名前で、さらに静的に利用できるところまでを学習した。

今回はAuth::guard()について、詳しく見てみる。

◆Auth::guard()について

config.php\app.php内を見ると、
サービスプロバイダは Illuminate\Auth\AuthServiceProvider::class
使うAliasは 'Auth' => Illuminate\Support\Facades\Auth::class
となっていることがわかるので、

Illuminate\Auth\AuthServiceProvider
public function register()
{
    $this->registerAuthenticator();

    $this->registerUserResolver();

    $this->registerAccessGate();

    $this->registerRequestRebindHandler();
}

register(バインド(登録)するメソッドの中に、4つもメソッドを呼んでる。)どうやら、後の記述を見ると、$this->registerAuthenticator();がサービスコンテナに名前'auth'で登録しているので見る。

protected function registerAuthenticator()
{
    $this->app->singleton('auth', function ($app) {
        $app['auth.loaded'] = true;

        return new AuthManager($app);
    });

    $this->app->singleton('auth.driver', function ($app) {
        return $app['auth']->guard();
    });
}

どうやら、Authファサードを呼ぶときは、AuthManagerクラスが呼ばれているらしいので見る。

public function __construct($app)
{
    $this->app = $app;

    $this->userResolver = function ($guard = null) {
        return $this->guard($guard)->user();
    };
}

呼ばれたときに自身のクラスのプロパティappにサービスコンテナの情報を持たしている。

public function guard($name = null)
{
    $name = $name ?: $this->getDefaultDriver();

    return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name);
}

同じAuthManager内にいた。

public function getDefaultDriver()
{
    return $this->app['config']['auth.defaults.guard'];
}

guardメソッドの最初で、$name$this->app['config']でサービスコンテナに名前'config'で登録したものを解決(取り出し)している。そのあとに['auth.defaults.guard']で、自分のconfg\auth.phpに登録したdefaults.guardを見ると、デフォルトではwebとなっている。つまり$name='web';

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."
    );
}
protected function getConfig($name)
{
    return $this->app['config']["auth.guards.{$name}"];
}

guardメソッドの中の\$this->guards[$name]には、最初何も入っていないので、resolveメソッドがよばれる。
resolveメソッドの\$configには、["auth.guards.{$name}"]今回なら\$name='web'なので、$config = [ 'driver' => 'session', 'provider' => 'users']
が入る。
ちなみに、Laravelのauthの設定ではdriverに認証方法、providerには認証情報へのアクセスするものが入る。

$driverMethod = 'create'.ucfirst($config['driver']).'Driver';

\$config['driver']はデフォルトではsessionなので、ucfirst関数で最初を大文字にして、

$driverMethod = 'createSessionDriver'
if (method_exists($this, $driverMethod)) {
    return $this->{$driverMethod}($name, $config);
}

自身のクラスにメソッド(createSessionDriver)があるか調べる。

public function createSessionDriver($name, $config)
{
    $provider = $this->createUserProvider($config['provider'] ?? null);

    $guard = new SessionGuard($name, $provider, $this->app['session.store']);

    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;
}

\$nameにはweb、$configには[ 'driver' => 'session', 'provider' => 'users']が入ってるので、

public function createUserProvider($provider = null)
{
    if (is_null($config = $this->getProviderConfiguration($provider))) {
        return;
    }

    if (isset($this->customProviderCreators[$driver = ($config['driver'] ?? null)])) {
        return call_user_func(
            $this->customProviderCreators[$driver], $this->app, $config
        );
    }

    switch ($driver) {
        case 'database':
            return $this->createDatabaseProvider($config);
        case 'eloquent':
            return $this->createEloquentProvider($config);
        default:
            throw new InvalidArgumentException(
                "Authentication user provider [{$driver}] is not defined."
            );
    }
}
protected function getProviderConfiguration($provider)
{
    if ($provider = $provider ?: $this->getDefaultUserProvider()) {
        return $this->app['config']['auth.providers.'.$provider];
    }
}

今回は\$providerが'users'なので、return [$this->app['config']['auth.providers.'.\$provider];はデフォルトでは

'users' => 
[
    'driver' => 'eloquent',
    'model' => App\User::class,
],

なので、['driver' => 'eloquent', 'model' => App\User::class]がはいる

createUserProviderの
if (isset($this->customProviderCreators[$driver = ($config['driver'] ?? null)])) {
    return call_user_func(
        $this->customProviderCreators[$driver], $this->app, $config
    );
}

\$driver変数に'eloquent'を入れながら、自身のプロパティ(customProviderCreators)の中身チェック、何も入れてないので次に進む

switch ($driver) {
    case 'database':
        return $this->createDatabaseProvider($config);
    case 'eloquent':
        return $this->createEloquentProvider($config);
    default:
        throw new InvalidArgumentException(
            "Authentication user provider [{$driver}] is not defined."
        );
}

で\$driver = 'eloquent'なのでreturn \$this->createEloquentProvider(\$config);

$configには、['driver' => 'eloquent', 'model' => App\User::class]がはいってる

protected function createEloquentProvider($config)
{
    return new EloquentUserProvider($this->app['hash'], $config['model']);
}

EloquentUserProviderにはHashManager(ハッシュ化管理)とApp\Userをわたす。
これがcreateUserProviderメソッドのreturnになるので、(これでユーザーを認証するものが決まった。)

public function createSessionDriver($name, $config)
{
    $provider = $this->createUserProvider($config['provider'] ?? null);

    $guard = new SessionGuard($name, $provider, $this->app['session.store']);

    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;
}

Sessionを利用して、認証を行うnew SessionGuardに入れる
https://qiita.com/fagai/items/a70c937ab7cf72f19dc2
SessionGuardクラスに、cookie・requests・eventをセットする

public function guard($name = null)
{
    $name = $name ?: $this->getDefaultDriver();

    return $this->guards[$name] ?? $this->guards[$name] = $this->resolve($name);
}

やっと戻ってきた。
デフォルトのAuth::guardでは、SessionGuardをセットしていて、セッションやリクエストのセットを行っている

まとめ

今回Auth::guard()にはなにが入るのかを詳しく見ていたが、auth.phpをもとに認証方法・認証するものに使うものを設定し、それをファサードに用意されたメソッドで使いやすいように利用者用のメソッドが作られていることがわかった。

Auth::guard()->guest()など
https://qiita.com/washio12/items/59f5cde23b4205973c6b