Laravel のルーティングでauthenticate middlewareを使って認証する3つの方法

Laravel ルーティングで特定の、もしくは全てのURLに対するアクセスに対して認証をしてから処理を始めたいケースについて紹介します。

具体的には "自分の情報を編集するマイページには、認証したユーザしか入ることはできない" みたいなケースの実装方法です。

方法を三つ紹介します。

1. routingファイルで個別のパスに対して指定する方法
2. routingファイルでグループを指定する方法
3. `RouteServiceProvider`で特定パス以下全てに指定する方法

## 環境

* Laravel 5.8
* PHP 7.2

## 前提条件（middleware の有効化）

`app/Http/Kernel.php` においてmiddlewareに名前をつけられています。おそらくLaravelをインストールするとデフォルトで以下のような記述（もしくはコメントアウトされている）があるのではないかと思います。

```php 
    protected $routeMiddleware = [
        'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
        // 以下略
    ]; 
```

コメントアウトされている場合には、使用できるように `//`を外してください。


## 方法１ routingファイルで個別のパスに対して指定する方法
公式ドキュメント（翻訳）の"認証"のセクション書かれているので軽く紹介しておきます。
参考: https://readouble.com/laravel/5.8/ja/authentication.html

```php
Route::get('profile', function() {
    // 認証済みのユーザーのみが入れる
})->middleware('auth');
```

> authミドルウェアをルートに対し指定するときに、そのユーザーに対し認証を実行するガードを指定することもできます。指定されたガードは、auth.php設定ファイルのguards配列のキーを指定します。

```php

public function __construct()
{
    $this->middleware('auth:api');
}
```

guradの指定に対応するファイルは以下のように書かれると思います。Providersの記述をもとに、DBからSelectしてきてユーザの確認をします。

```config/auth.php
    'guards' => [
        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],
    ],

    'providers' => [
        'users' => [
            // EloquentModelを指定するケース
            'driver' => 'eloquent',
            'model' => Path\To\EloquentModel\User::class,
        ],
    ],
```

## 方法2 routingファイルでグループを指定する方法
さて、上の方法でみた個別のRoutingに追加する方法ですが、いちいち指定するのは面倒だったり、設定し忘れでセキュリティ的な問題が起こってしまったりするので一括で指定したいところです。
同じルーティングファイル内でも、ログイン前のページは制限なし、一方でログイン後のページで認証あり、というような制限をしたい場合にこの方法が便利です。

routingについてのドキュメントを見ると、一括でmiddlewareを指定する方法があるようです。
参考: https://readouble.com/laravel/5.8/ja/routing.html

レート制限の項目に書いてあるのでちょっとわかりづらいのですが、group化したものに対して以下のようにmiddleware設定をすることができます。

```php
Route::middleware('auth:api', 'throttle:60,1')->group(function () {
    // この中に書いたルーティング全てに適用される
    Route::get('/', 'IndexController@index');
});

// ここには適用されない
Route::get('/piyo', 'IndexPiyoController@index');
```

また、古い方法（Laravel5.2のドキュメントに書いてある）のようですが、以下のような方法で書くこともできます。
参考: https://readouble.com/laravel/5.2/ja/routing.html

```php
Route::group(['middleware' => 'auth:api'], function () {
    Route::get('/', 'IndexController@index');
});
```


## 方法3 RouteServiceProvider で指定する方法

ログインが必要なページから投げられるAjax通信なんかは、全てのパスに対して一括で指定したいところです。
その場合には、グループ化する方法より、RouteServiceProviderで指定する方法がより便利です。

routingファイルとして `routes/api/service.php` があったとして、routingのマッピングをするとともにmiddlewareを設定します。

```app/Providers/RouteServiceProvider.php
use Illuminate\Foundation\Support\Providers\RouteServiceProvider as ServiceProvider;

class RouteServiceProvider extends ServiceProvider
{

    // このメソッドは親のIlluminate\Foundation\Support\Providers\RouteServiceProviderから呼び出されています
    public function map()
    {
        Route::prefix('api')
            // このprefix以下にあるものに全てmiddlewareが適用される
            ->middleware(['auth:api'])
            // Controllerがどこにあるか指定
            ->namespace($this->namespace . '\Api')
            ->group(base_path('routes/api/service.php'));
    }
```

これを `config/app.php` で providers 設定をします。

```config/app.php

    'providers' => [
        App\Providers\RouteServiceProvider::class,
    ],

```

参考: https://readouble.com/laravel/5.8/ja/routing.html

## 終わりに
ここら辺は複雑なので、どのレイヤで認証を入れているのだろう？というのが分かりづらくなりがちだと思います。
しかしそんなに実装パターンがあるわけではないので、この三つを押さえておけばコードリーディングする助けになるのかなと考えてこの記事を書きました。
もっとこういう方法があるよ！ とかここが間違っているとかあれば、修正リクエストやコメントいただけると幸いです。