Laravel：Email Verification（メールアドレスの確認）を使う



# 概要

Webサービスでアカウントを作成する時、メールアドレスの確認メールが届く。

Laravel 5.7から、この確認メールを送信する機能が追加されたそうなので、試してみる。

参考： :link: readouble.com [メール確認](https://readouble.com/laravel/5.7/ja/verification.html)

##▼ 動作確認環境
- PHP 7.1.21
- Laravel 5.7


##▼ 前提

`php artisan make:auth`で、アカウント作成・ログイン機能・パスワードリマインダーがすでに準備されていることが前提です。


# 設定していこう

##▼ app/User.php を編集する



```diff

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

- class User extends Authenticatable
+ class User extends Authenticatable implements MustVerifyEmailContract
{
+   use MustVerifyEmail, Notifiable;

}

```

`MustVerifyEmail`に対して`as MustVerifyEmailContract` という風にエイリアスを設定しているのは、クラス内で追加している `use MustVerifyEmail ...` のトレイトと名前が競合しないようにするため。

##▼ routes/web.php を編集する

```diff
- Auth::routes();
+ Auth::routes(['verify' => true]);
```


# 動作確認

この時点でアカウント作成を試してみます。

画面には「ログインしました!」という表示。

![emailVerificaton_browser.png](https://qiita-image-store.s3.amazonaws.com/0/275623/e0c7a428-a844-d896-a888-03007dc05336.png)


メールはちゃんと届きました。

![emailVerification.png](https://qiita-image-store.s3.amazonaws.com/0/275623/8aab4906-4e32-d799-cba6-c54f45660065.png)



メールアドレスが有効かどうか確認することと、アカウントを作成することとは別です。
そのため上のような状況になり、
この段階でも記事の投稿などができてしまいます。

これを防ぐために、middlewareのverifiedを使います。
これを使うことで、メールアドレスが確認済みの場合のみ投稿ができるようにします。



# 修正する


##▼ ルーティングを修正する

メールアドレス未確認にもかかわらず「ログインしました！」となってしまう点から修正したいので、まずルーティングを修正します。

参考： :link: readouble.com [保護下のルート](https://readouble.com/laravel/5.7/ja/verification.html#protecting-routes)


`->middleware('verified')` を設定しておきます。
こうすることで、メール確認が済んでいない状態でhomeにアクセスされた場合は
email/verify にリダイレクトするようになります。

```php:routes/web.php

Route::get('/home', 'HomeController@index')->middleware('verified');
```

このように設定してからアカウント作成を試すと、画面はこのようになってくれます。

![emailVerification_afterSetmiddleware.png](https://qiita-image-store.s3.amazonaws.com/0/275623/b45629fe-ae7b-82d9-68f6-64a99c4b0c62.png)





##▼ 記事の投稿に制限をかける

###- route/web.php で修正する方法
記事を投稿したり編集・削除する時にもverifiedを使いたいです。

以下の要領で全部に`->middleware('verified')`をつけてもいいのですが、
ちょっと手間です。

```php
Route::post('/posts', 'PostsController@create')
	->middleware('verified');

Route::post('/posts', 'PostsController@store')
	->middleware('verified');
```


###- コンストラクタで対応する方法

`__construct()`の中に書くことで
「基本的にverifiedが必要、ただしindexとshowを除く」とできます。

```php:app/Http/Controllers/PostController
    public function __construct()
    {
        $this->middleware('verified')->except(['index', 'show']);
    }
```

UserControllerは少し変えます。
メールアドレスの確認が完了していなくても、退会だけはできるようにします。


※ `->middleware('verified')`はログイン中でメアドの確認が完了済み
`->middleware('auth')`はログイン中でメアドの確認が未完了

```php:app/Http/Controllers/UserController.php

    public function __construct()
{
        $this->middleware('auth')->only('destroy');
        $this->middleware('verified')->except(['index', 'show', 'destroy']);
    }
```


# Email Verification が終わった時の飛び先

![emailVerification.png](https://qiita-image-store.s3.amazonaws.com/0/275623/8aab4906-4e32-d799-cba6-c54f45660065.png)

届いたメール中のボタンをクリックした時、飛び先はデフォルトで/home になっていると思います。

これをカスタマイズします。

##▼ 飛び先を変える

ここが/home となっているので /verified という風にしてみます。

```php:app/Http/Controllers/Auth/VerificationController.php

    /**
     * Where to redirect users after verification.
     *
     * @var string
     */
    protected $redirectTo = '/verified';
```



##▼ route/web.php

verifiedに行くにはもちろん`->middleware('verified')`が必要です。

```php:route/web.php

Route::get('/verified', function(){
	return view('auth.verified');
})->middleware('verified');
```


##▼ Viewを作る

resources/views/auth/verified.blade.phpを新しく作ります。

```html:resources/views/auth/verified.blade.php

@php
    $title = __('You\'ve verified your email address.');
@endphp

@extends('layouts.myapp')

@include('layouts.header')

@section('content')
<div class="container">
    <div class="row justify-content-center">
        <div class="col-md-8">
            <div class="card">
                <div class="card-header">{{ __('You\'ve verified your email address.') }}</div>

                <div class="card-body">
                    {{ __('Let\'s get started.') }}
                </div>
            </div>
        </div>
    </div>
</div>
@endsection


```


##▼ ja.jsonに追記

```json:resources/lang/ja.json
    "You've verified your email address.":"メールアドレスの確認が完了しました。",
    "Let's get started.":"さっそく始めてみましょう。"
```


これで完成。
verified.blade.phpには、初めてサービスを利用する人向けのTIPSなど表示できると良さそうです。


# 参考

 :link: [【Laravel 5.7】新たにメールアドレスの確認機能(Email Verification)が追加。使い方と仕組みを紹介します。](https://public-constructor.com/laravel57-email-verification/)

 :link: Qiita [Laravel5.7: ユーザー登録確認用のメールを送信する](https://qiita.com/sutara79/items/c913d7eedd5456635ea5)