Laravelの認証の仕組み

## Laravelの認証

Laravelでは、プロジェクトディレクトリで下記のコマンドを打つと、スカフォールドで基本的な**認証画面の作成**と**ルーティングの設定**を行ってくれます。

```
$ php artisan make:auth 
```

### 認証の仕組み
認証は**ミドルウェア**を使って実現しています。
**ミドルウェア**とはOSとアプリケーションの間に入って処理を行ってくれるものです。
リクエスト時やレスポンス時にフィルタリングを行うなどしてくれます。
ログインの認証では、**web,guest,auth**の3つのミドルウェアを使用しています。

##### 認証前
![認証前.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140953/ec3e0adf-6e07-cce4-14e7-7d5ddbe9bf16.png)

##### 認証後
![認証後.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140953/99cdd777-71cb-1bf9-2a6f-521968172c73.png)

参考：
[Laravelの認証について](https://www.slideshare.net/nodat/laravel-67450545)
[認証 5.5 Laravel](https://readouble.com/laravel/5.5/ja/authentication.html)

## 認証と認可の違い

一言で説明すると、
認証(Authentication)は、その**ユーザが誰か**を判断すること
認可(Authorization)は、そのユーザで**何ができるか**を判断すること
です。

![認証と認可.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140953/b65d6e64-07c6-4073-403f-c372103b3470.png)

参考：[よくわかる認証と認可 ｜ DevelopersIO](https://dev.classmethod.jp/security/authentication-and-authorization/)

## 環境
Laravel 5.5.45
Homestead 8.2.0
Vagrant 2.2.4
Virtual Box 7.2.1

## 実際の中身
実際の中身を見ていきます。

### 作成される認証画面

![スクリーンショット 2019-04-21 12.32.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140953/6f00a9f5-205f-0609-e8e3-8f6a11851e7a.png)
`resources/views`にログイン画面、登録画面、パスワードリセットの画面、ホーム画面などが生成されています。

### 設定されるルーティング

`$ php artisan route:list`を実行してルーティングを確認します。
![スクリーンショット 2019-04-21 9.33.12.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/140953/069917d3-ae7e-0a4a-654d-375449a29810.png)
ここでMiddlewareのカラムに注目すると、それぞれ
ログイン前は**web,guest**のミドルウェア
ログイン後は**web,auth**のミドルウェア
を使用していることがわかります。

## ミドルウェアについて

### ミドルウェアの定義
`app/Http/Kernel.php`でミドルウェアの定義をしています。
ファイル名である**カーネル**とはOSの中核部分の処理を行ってくれるものです。
このファイルでは3つの変数があります。

- `$middleware` ・・・全ての処理に共通して処理を行うミドルウェアを定義します。各ルートを呼ばれたときに実行されます。
- `$middlewareGroups`・・・複数のミドルウェアをグループとして定義します。
- `$routeMiddleware`・・・ 単体で使うミドルウェアをキーと共に定義します。

認証に使用する**web, guest, auth**を以下に抜粋します。

```app/Http/Kernel.php
   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,
        ],
   ]

    protected $routeMiddleware = [
        'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
        'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    ];
```

クラスの中身を見てみます。F12キーで定義ファイルへジャンプできます。
ミドルウェアでは、**handle関数**に処理をするプログラムを記載し、**next**でアプリケーションを次に進めます。

ミドルウェアの中身の説明について、こちらの記事から引用させていただきます。
[[Laravel]ミドルウェアを整理してLaravelを軽くする - Qiita](https://qiita.com/kurikazu/items/0c57f050f5dfef02b23e)

### webの中身
>\App\Http\Middleware\EncryptCookies::class
Cookie の暗号化/復号化処理を行う機能
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class
指定された Cookie を Response ヘッダに登録する機能
\Illuminate\Session\Middleware\StartSession::class
Session の生成や取得などを行う機能
\Illuminate\View\Middleware\ShareErrorsFromSession::class
Session に保存されたエラー情報を View にセットする機能
\App\Http\Middleware\VerifyCsrfToken::class
CSRF を防ぐためのトークンの発行やチェックを行う機能
\Illuminate\Routing\Middleware\SubstituteBindings::class
Route Model Binding を実行する機能（Laravel5.3から追加）

### authの中身
>auth（\Illuminate\Auth\Middleware\Authenticate::class）
特定のルートへのアクセスに対してユーザー認証を行う機能

### guestの中身
>guest（\App\Http\Middleware\RedirectIfAuthenticated::class）
認証済かチェックし、認証済であれば /home にリダイレクトする機能

### ミドルウェアの使用
ミドルウェアの使用方法には主に二つやり方があります。
（1）ルータでミドルウェアを使用する
（2）コントローラでミドルウェアを使用する

webのミドルウェアは`routes/web.php`のルートに対して使用されています。

```app/Providers/RouteServiceProvider.php
class RouteServiceProvider extends ServiceProvider
{
    protected function mapWebRoutes()
    {
        Route::middleware('web')
             ->namespace($this->namespace)
             ->group(base_path('routes/web.php'));
    }
}
```

guestやauthのミドルウェアは、各コントローラのコンストラクタで使用されています。

```app/Http/Controllers/HomeController.php
class HomeController extends Controller
{
    public function __construct()
    {
        $this->middleware('auth');
    }
}
```

```app/Http/Controllers/Auth/LoginController.php
class LoginController extends Controller
{
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }
}
```

参考：[ミドルウェアについて - Laravel学習帳](https://laraweb.net/practice/1396/)

## 認証・認可のカスタマイズ

Laravelでは、デフォルトで`config/auth.php`に認証の設定がされています。

マルチ認証など独自の認証のカスタマイズをしたい場合は、Guard(ガード)やProvier(プロパイダ)、
認可のカスタマイズをしたい場合は、Gate(ゲート)やPolicy(ポリシー)あたりを自分で設定する必要があります。

参考：
[認証 5.5 Laravel](https://readouble.com/laravel/5.5/ja/authentication.html)
[認可 5.5 Laravel](https://readouble.com/laravel/5.5/ja/authorization.html)

# 最後に

記事に間違いや不明な点があれば遠慮なくご指摘ください。
私も勉強中の身なので、不足があればいろいろ教えてもらえたら嬉しいです。
ちなみにTwitterで認可と認証の違いがわからんって呟いたら教えてもらいました。笑
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">認証は、そのユーザが誰か<br>認可は、そのユーザが何ができるか</p>&mdash; シュプレ (@spre55) <a href="https://twitter.com/spre55/status/1118510364503601153?ref_src=twsrc%5Etfw">April 17, 2019</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

シュプレさんありがとうございます！