【Laravel】認証済みユーザーが"/register"にアクセスするとリダイレクトされるのはなぜか

## 初めに

タイトルの通りです。`RegisterController`コントローラーや`RegisterUsers`トレイトばかりに目が向いていて、ミドルウェアという選択肢を全く考えられなかったことへの戒めに記事に残しておきます。

## 前提

**環境**

* PHP `7.4.15`
* Laravel `6.20.16`
* laravel/ui　`1.3.0`

今回の認証機能は`laravel/ui`の以下のコマンド

```bash
php artisan ui:auth vue
```

によって提供されるものをそのまま使いました。

## 結論

先に答えを述べて、それから何故それが答えになるのかの説明をしていきたいと思います。

結論を言いますと、`App\Http\Controllers\Auth\RegisterController`クラスのコンストラクタに

```php:app/Http/Controllers/Auth/RegisterController.php
public function __construct()
{
    $this->middleware('guest');
}
```

という処理によって、`guest`という名前のミドルウェアが適用されているからでした。

`guest`ミドルウェアが追加されているコントローラは、認証済みユーザーからはアクセスできないようにミドルウェアによってガードされるようになります。

ではこの処理がどのように動作しているかを見てみましょう。

## ミドルウェア`guest`

`guest`ミドルウェアがどんな処理を行うかは`App\Http\Kernel`をみればわかります。

`App\Http\Kernel`は

* 適用させるミドルウェアを登録したり
* グループ分けを行ったり
* 今回の`guest`のようにミドルウェアに対して個別に呼び出しを行えるように別名を付けたり

といったミドルウェアに関する情報を扱っています。

`App\Http\Kernel`クラスを見てみると、

```php: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,
    'password.confirm' => \Illuminate\Auth\Middleware\RequirePassword::class,
    'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
// 後略
```

`$routeMiddleware`プロパティに、`[ミドルウェア名 => それの実装クラス]`というような形式の連想配列の形で、あるミドルウェアに対してどの実装クラスを実行するかの情報が保存されています。

このプロパティ中の`guest`キーに対応するものは`\App\Http\Middleware\RedirectIfAuthenticated`というクラスです。

名前からして、**認証済みであればリダイレクトを行う**という処理を担っていることが明らかですね。

ではこのクラスの実装を見てみましょう。

## `RedirectIfAuthenticated`クラスの処理

```php:app/Http/Middleware/RedirectIfAuthenticated.php
<?php

namespace App\Http\Middleware;

use App\Providers\RouteServiceProvider;
use Closure;
use Illuminate\Support\Facades\Auth;

class RedirectIfAuthenticated
{
    public function handle($request, Closure $next, $guard = null)
    {
        if (Auth::guard($guard)->check()) {
            return redirect(RouteServiceProvider::HOME);
        }

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

コメントを省くとこれだけの処理です。

リクエストを受けたときに実行されるメソッドである`handle()`メソッドの中身を見てみましょう。

まず`Auth::guard($guard)->check()`で既にユーザー情報があるかを判断しています。

既にユーザー情報がある、つまりログイン済みであれば

```php
return redirect(RouteServiceProvider::HOME)
```

で`RouteServiceProvider::HOME`にリダイレクトする、という処理を行っています。

この処理から、`App\Providers\RouteServiceProvider`クラスの`HOME`定数を変更すればリダイレクト先を変更できるということもここから読み取れますね。

ユーザー情報がまだ無ければこのミドルウェアでは何もせず、`$next($response)`によって次のミドルウェアへ処理を渡しています。

以上のことから、確かにこのミドルウェアによって認証済みユーザーに対してのアクセスガードが実装されていることが分かりました。

## 終わりに

認証済みユーザーが`/register`にアクセスしたときにリダイレクトする処理は、`guest`ミドルウェア、つまり`\App\Http\Middleware\RedirectIfAuthenticated`クラスによって提供されていることが分かりました。

ここでは各処理の詳細については深くは追わず、簡略化した説明となっています。

もし各処理の詳細（たとえば、ミドルウェアの実行される流れだったり、リダイレクト関数の実装）が気になる方がいらっしゃいましたら、ぜひ一度`laravel`のソースコードを深堀して追ってみるという経験をなさってみてはいかがでしょうか。