Laravelのmiddleware authを理解したい


# 環境
Laravel 5.2
PHP 7.0
ubuntu14.04

# 目的
Laravelのmiddlewareのauthを理解する
※middlewareのauthは、ログイン状態のチェックを行うもので、ログイン処理ではないので注意
※ログイン処理は、Illuminate\Foundation\AuthのAuthenticatesUsersを調査すべし


# 調査
* middlewareの使い方は、route.phpにRoute::groupで指定する

```route.php
  Route::group(['middleware' => ['auth']], function () {
        // この中はログインされている場合のみルーティングされる
        Route::get('/', function () {
            return view('dashboad');
	});
  });
```

* Http/Kernel.phpにて「auth」というaliasを登録している

```Http/Kernel.php
protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
```

## \App\Http\Middleware\Authenticateでやってること
 * handleが定義されている(middlewareはこのhandleメソッドが呼ばれる)
 * 認証は、`Auth::guard($guard)->guest()`が行っているようだ。
 * 認証NGならログインへリダイレクトしている
 * 認証OKなら`return $next($request);`
    * `$next`は、本来のrouteが設定される(たとえば`/`とか)と理解。

# 前半 (`Auth::guard($guard)->guest()`の`Auth::guard()`部分)

## Auth::guard($guard)がやってること
* ソースファイル:vendor\laravel\framework\src\Illuminate\Auth\AuthManager.php

```\Illuminate\Auth\AuthManager.php
    /**
     * Attempt to get the guard from the local cache.
     *
     * @param  string  $name
     * @return \Illuminate\Contracts\Auth\Guard|\Illuminate\Contracts\Auth\StatefulGuard
     */
    public function guard($name = null)
    {
        $name = $name ?: $this->getDefaultDriver();

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

* $nameが`null`の場合、`getDefaultDriver()`がコールされ、configのauth.defaults.guardの値(デフォルトは'web')がセットされる
* return値は三項演算子で求められる
* `$this->guards['web']`のissset()がfalseの場合、`$this->resolve($name)`を実行する
* `$this->resolve($name)`取得した`$gurad`(↓resolveを参照)を返す。

## resolve($name)がやってること
* まず、configのauth.guards.{$name}の値。すなわち、→ auth.guards.webの値を取得する
  * デフォルト：`auth.guards.web = ['driver'=>'session','provider'=>'user']`
* `'create'.ucfirst($config['driver']).'Driver';`でdriverMethodを生成。
 * driverは「session」なので、 `createSessionDriver()`となる
* createSessionDriver()メソッドの実行し、返り値をreturn

## createSessionDriver()がやってること
* createSessionDriver()はAuthManagerクラスにある
* createUserProvider()を呼び出し、Provider情報を取得(↓createUserProvider参照)
* SessionGuard()をnew(↓)
    * `$guard = new SessionGuard($name, $provider, $this->app['session.store']);`
* $guradに`Illuminate\Cookie\CookieJar`(暗号化用クッキーの設定？)をセット
* $guradに`Illuminate\Events\Dispatcher`(イベントのListen情報)をセット
* $guradに`Illuminate\Http\Request`(リクエストパラメータ)をセット
* $guradを返す。
* **つまり、前半(Auth::guard()部分)では、SessionGuardクラスのオブジェクト取得が目的**

## createUserProvider()がやってること
* configのauth.providers.{$provider}の値 → `auth.providers.users`の値を取得する
  * デフォルト：`auth.providers.users = ['driver'=>'eloquent','model'=>'App\User']`
* 「何を使って、どこからUser情報を取得するか」というのを取得する。
* デフォルトでは、「eloquentを使って、App\Userモデルの情報をとる」ということ


# new SessionGuard()でやっていること
* ソースファイル：`Illuminate\Auth\SessionGurad.php`

``` SessionGurad.php
    public function __construct($name,
                                UserProvider $provider,
                                SessionInterface $session,
                                Request $request = null)
    {
        $this->name = $name;
        $this->session = $session;
        $this->request = $request;
        $this->provider = $provider;
    }
```
* セッションやリクエストのセットを行っている

*** 

# 後半 (`Auth::guard($guard)->guest()`の`->guest()`部分)
## guest()はどこにあるか？
* Auth::guard()にて、SessionGuardクラスのオブジェクトが返ってきているので、SessionGuardクラスのguest()を見てみる
* しかし、Illuminate\Auth\SessionGuard.phpにはguest()がない
* `use GuardHelpers;`を行い、GuardHelpersクラスをトレイトしている
* Illuminate\Auth\GuardHelpers.phpにguest()がある

# guest()がやっていること
* ソースファイル：`Illuminate\Auth\GuardHelpers.php`
* `$this->check()`を呼び出し
* `$this->check()`は、Illuminate\Auth\SessionGuard.phpの`$this->user()`を呼び出し

```GuardHelpers.php
    public function guest()
    {
        return ! $this->check();
    }
```

```GuardHelpers.php
    public function check()
    {
        return ! is_null($this->user());
    }
```

* `$this->user()`はGuardHelperではなく、SessionGuardにある(戻った…)
* `$this->user()`の結果がnullだと、check()は`false`、guest()は`true`を返す
    * guest() == `true`：ログインしていないということ

# SessionGuardのuser()がやっていること

* ソースファイル：`Illuminate\Auth\SessionGuard.php`
* `$this->loggedOut`変数をチェック。Logoutされていれば`true`が設定される
    * ログアウトしてもセッションが残っているとかの予防？
* $idがsessionに保存されているかチェック

```php
$id = $this->session->get($this->getName());
```
* Sessionに$idがあれば、Usersテーブルを検索し、ログイン中ユーザーを返す

```php
if (! is_null($id)) {
   $user = $this->provider->retrieveById($id);
}
```

* remenber meが有効かチェック
* `$this->getRecaller()`でクッキーに保存されているトークンを取得

```php
protected function getRecaller()
{
    return $this->request->cookies->get($this->getRecallerName());
}
```

* `$this->getUserByRecaller()`でUsersテーブルを検索
    * トークンは、remenber meを有効にするとログイン時にUsersテーブルに保存される

* Sesssion、もしくはRecallerで$userがあればログインユーザーを返す
* ログインユーザーがいない場合、nullが返る(ログインしていないとなる)