【Laravel】自作のミドルウェア内でログインユーザー情報が取得できなかった原因


ログインしているユーザー情報（ユーザーID）をログに出力したいなと思い、ミドルウェアを作成したのですが`Auth::id()`でうまく取得できなかった。


# 作ってみた

## 環境

- Laravel 5.8

## ミドルウェアを作成

```UserIdLogMiddleware.php
<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;

class UserIdLogMiddleware
{

    /**
     *
     *
     * @param $request
     * @param Closure $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        try{
            Auth::check()
                ?Log::info('ユーザーID:'.Auth::id())
                :Log::info('未ログイン');
        }catch(\Exception $exception){
            //ログ出力できなくてもエラーにしない
            Log::warning('ユーザーIDの取得に失敗');
        }

        return $next($request);
    }
}
```

## ミドルウェアを登録

今回は全部のリクエスト時に適用できればいいから`$middleware`に設定しよう。（今思えばこれが間違いの始まりだった・・・）

```/app/Http/Kernel.php
    protected $middleware = [
        \App\Http\Middleware\TrustProxies::class,
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
        \App\Http\Middleware\UserIdLogMiddleware::class,    //ここに追加
    ];

```

# 実行結果
```
local.INFO: 未ログイン
```

・・・ログインIDが取得できていない。

# 原因

ブレークポイント貼って色々と処理を辿ってみたところミドルウェアの実行順番は、

1. グローバルミドルウェア（$middleware）
2. ルートミドルウェア（$routeMiddleware）

となっていた。なるほど。

と、ここで、ふと思いました。

__ログインユーザ情報ってなんで取得できるんだろう？？__ 

そういえば、ログイン済みユーザだけのルーティングってauthミドルウェアを適用しているし、

```
Route::get('profile', function() {
    // 認証済みのユーザーのみが入れる
})->middleware('auth');
```
(<a href="https://readouble.com/laravel/5.8/ja/authentication.html#protecting-routes">Laravel日本語ページ</a>から引用)


その中のコントローラとかで`Auth::id()`ってやるし、、、

もしや、認証情報ってauthミドルウェア（\App\Http\Middleware\Authenticate）を実行した後じゃないと、`Auth`ファサードで取れないのでは？
考えてみれば、そりゃそうだ。

と、ここでKernelクラスをもう一度見てみると、

```/app/Http/Kernel.php
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    ];
```

うん、`auth`ミドルウェアはルートミドルウェア（$routeMiddleware）に書いてある。

## 何がダメだったのか

__`auth`ミドルウェアが動く前に実行されていたから！__

# 修正

- グローバルミドルウェア　→ ルートミドルウェアに変更 
- そして`auth`ミドルウェアの後に動かす

修正結果はこちら

```/app/Http/Kernel.php
<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    /**
     * The application's global HTTP middleware stack.
     *
     * These middleware are run during every request to your application.
     *
     * @var array
     */
    protected $middleware = [
        \App\Http\Middleware\TrustProxies::class,
        \App\Http\Middleware\CheckForMaintenanceMode::class,
        \Illuminate\Foundation\Http\Middleware\ValidatePostSize::class,
        \App\Http\Middleware\TrimStrings::class,
        \Illuminate\Foundation\Http\Middleware\ConvertEmptyStringsToNull::class,
//        \App\Http\Middleware\UserIdLogMiddleware::class,    //ここに追加
    ];

    /**
     * The application's route middleware groups.
     *
     * @var array
     */
    protected $middlewareGroups = [
        'web' => [
            \App\Http\Middleware\EncryptCookies::class,
            \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
            \Illuminate\Session\Middleware\StartSession::class,
            // \Illuminate\Session\Middleware\AuthenticateSession::class,
            \Illuminate\View\Middleware\ShareErrorsFromSession::class,
            \App\Http\Middleware\VerifyCsrfToken::class,
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
            'user.log',  //グループに入れて全リクエストに適用する
        ],

        'api' => [
            'throttle:60,1',
            'bindings',
        ],
    ];

    /**
     * The application's route middleware.
     *
     * These middleware may be assigned to groups or used individually.
     *
     * @var array
     */
    protected $routeMiddleware = [
        'auth' => \App\Http\Middleware\Authenticate::class,
        'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
        'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
        'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
        'can' => \Illuminate\Auth\Middleware\Authorize::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
        'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
        'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
        'user.log' => \App\Http\Middleware\UserIdLogMiddleware::class,  //こっちに移動
    ];

    /**
     * The priority-sorted list of middleware.
     *
     * This forces non-global middleware to always be in the given order.
     *
     * @var array
     */
    protected $middlewarePriority = [
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\Authenticate::class,
        \App\Http\Middleware\UserIdLogMiddleware::class,  //実行の順番を指定しておく
        \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \Illuminate\Auth\Middleware\Authorize::class,
    ];
}
```

# 修正後の実行結果
```
local.INFO: ユーザーID:2
```

出力された！