【Laravel8】breezeでメール認証を爆速導入する


Laravelには標準で認証の仕組みが複数用意されていますが、公式Docを見るとLaravel初心者の場合Breezeを使ってLaravelの認証に慣れていきましょうという旨が書かれています。

> Laravel Breezeは、Laravelアプリケーションを構築するためのシンプルで最小限の開始点を提供しますが、Jetstreamはより堅牢な機能と、追加のフロントエンドテクノロジースタックで、その機能を強化します。Laravelを初めて使用する場合は、Laravel Jetstreamへ進む前に、Laravel Breezeで勘所を掴むことをおすめします。

https://readouble.com/laravel/8.x/ja/starter-kits.html

というわけで従順にBreezeを導入してみたのですが、メール認証の実装で小一時間ほど詰まったので、備忘録を兼ねて記録に残しておきたいと思います。

## 環境、要件

 - Docker
 - docker compose
 - PHP8.1.1
 - Laravel8

※この記事を執筆した2022-03-13時点で、既にLaravel9がリリースされています。今後のLTSはLaravel9なので可能なのであれば9を使う方が良いと思います。

## 環境構築

以下のリポジトリをcloneしたら、とりあえず私と同じ環境にはなります。

https://github.com/T-unity/laravel-template

※一応ビルドの手順とかはルートのREADMEに書いているのですが、分かりづらければコメントしてください。shファイルも用意しているのでそれを使ってもらえれば結構手間も減るかなと思います。

ちなみに上記の環境は、@ucan-labさんの記事を参照させていただきました。大変分かりやすい記事をありがとうございます。

https://qiita.com/ucan-lab/items/56c9dc3cf2e6762672f4

ご自分で1から環境を作りたい方は、上記の記事を参照されるのが良いかと思います。

## breezeの導入

いきなりすっ飛ばして申し訳ありませんが、Breezeの導入については今回の本題ではないので割愛します。
基本readoubleの公式Docを読みつつコマンドを入力したら大丈夫かと思います。

以下コミットとだいたい同じ感じになっていればBreezeの導入に成功しているかと思います。
（差分かなり多い、、、）

https://github.com/T-unity/laravel-breeze/commit/0ddb5558485e91eb61c9cd8353dfc52fee4a322d

Breezeをインストールして、以下ドキュメントルートの右上に「Log in」と「Register」のリンクができていればOKです。

![スクリーンショット 2022-03-13 22.26.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684929/3253e33d-ffbb-f8c1-d06c-aaa926721efb.png)

※もし詰まるようであればコメントしてください。

## メール認証の導入。

以下のコミットで実装しています。

https://github.com/T-unity/laravel-breeze/commit/603ed9c7d5cb6e1f9751efe423aca8f05912010b

### 参考記事紹介

早速実装していきますが、取り急ぎ今回参考にさせていただいた記事を記載します。

 - 実装

https://dev.to/dendihandian/laravel-email-verification-3lfa

https://qiita.com/leonyaochi/items/b1e1b6bb73143bddd114

https://qiita.com/nekyo/items/03e50b4d0dd6f09287d6

 - 動作確認

https://qiita.com/ucan-lab/items/49e7f4986564f68e95c4

### いざ実装

以下2つのファイルを更新します。

 - app/models/User.php
 - routes/web.php

```app/models/User.php

// use Illuminate\Contracts\Auth\MustVerifyEmail;
+ use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;
+ use Illuminate\Auth\MustVerifyEmail;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
// use Laravel\Sanctum\HasApiTokens;

// class User extends Authenticatable
class User extends Authenticatable implements MustVerifyEmailContract
{
    use HasFactory, MustVerifyEmail, Notifiable; // MustVerifyEmailを追加
```

```routes/web.php
Route::get('/dashboard', function () {
    return view('dashboard');
// })->middleware(['auth'])->name('dashboard');
})->middleware(['auth', 'verified'])->name('dashboard');
// ミドルウェアのverifiedを追加
```

ここまでで、一応認証ロジックはできました。

### 動作確認を行う

実際動作確認をしたいのですが、上記だけだとおそらく以下のようなエラーが出るかなと思います。

`Connection could not be established with host mailhog :stream_socket_client():`

以下の記事に従って対応しましょう。

https://qiita.com/ucan-lab/items/49e7f4986564f68e95c4

言うても、docker-compose.ymlに以下のサービスを追加するだけです。

```docker-compose.yml
  mail:
    image: mailhog/mailhog
    ports:
      - 8025:8025

# インデントの深さには注意してください。
# もしまだエラーが出続ける場合は、一旦docker compose downしてから再度起動してみてください。
```

対応すると以下のような認証画面が表示されて、メール認証を行っていないユーザーがダッシュボードにログインできない事を確認できるはずです。

![スクリーンショット 2022-03-13 22.41.38.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/684929/f65df521-1e00-8801-85de-5b67b9b4a236.png)


## 個人的に詰まったポイント

非常にお恥ずかしいのですが、`app/models/User.php`の名前空間をインポートするあたりで、タイポに気づかず

```
User cannot use Illuminate\Contracts\Auth\MustVerifyEmail - it is not a trait
```

みたいなエラーを出し、40分くらい詰まってしまいました。
筋トレで追い込んで脳が疲れていたせいだと言い訳させてください、、

use命令が増えてくると結構可読性も落ちてくるので、もし上記のようなエラーが出る場合はこのあたりを疑ってみるのも良いかもしれません。

基本はBreezeのメール認証実装で詰まることってそんなにないのかなと思いますが、もし同様に詰まってしまった方がいれば参考にしていただければ幸いです。

## 追加課題

以下のあたりはまだできていないのでこの後やります

 - 日本語化（たぶんすぐできる）
 - パスワードリセット（デフォでついてるっけ？）
 - メールアドレス変更（これたぶんBreezeでは提供されてないよね？）

## 追記

今回の認証だと、メールアドレスのチェックが行われないみたいですね。
メールアドレスで認証トークンを送信する場合は、間違ってメールアドレスを入力したケースに備えて

1. まず最初にメールアドレスを入力させる
1. 入力されたメールアドレス宛に認証トークン付きのメールを送る
1. トークンをクリックしたら、会員登録画面に遷移する

みたいなフローにした方が良さそうです。
間違ってメールアドレスに認証メールが送られて、しかもそれが実在するアドレスだった場合結構な事故ですからね、、、

パスワードの再設定とかも考慮が必要な箇所かなと思います。