【Laravel】ユーザ登録時にメール認証する(v5.7以上)

# メールを使った登録認証
標準で用意されている auth の laravel の認証は、
ユーザ登録すると直ぐログインできてしまった。これではメアドが正しいか確認できない。
Laravel5.7以降には、ユーザ登録時に仮メールを送信し、それに記載されているリンクを踏むことで本登録され、
以後ログインできるようになる機能が用意されている。
users テーブルのマイグレーションには 'email_verified_at' というフィールドが追加されていると思うので、
認証系を作成して、dbの設定をし、マイグレーションしておく。
## Userの変更
Illuminate\Contracts\Auth の MustVerifyEmail に別名を設定して、Illuminate\Auth の MustVerifyEmail を使うよう変更する。

```php:/app/User.php
- 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 Notifiable;
+    use MustVerifyEmail, Notifiable;
```
## ルーターの変更
メール確認関連のルーティングを有効にする。

```php:/routes/web.php
- Auth::routes();
+ Auth::routes(['verify' => true]);
```
## ミドルウェアの認証を verified に変更する。
auth だと本登録しなくてもログインできてしまうので verified に変更する。

```php:/app/Http/Controllers/HomeController.php
class HomeController extends Controller
{
    public function __construct()
    {
-        $this->middleware('auth');
+        $this->middleware('verified');
```
# 日本語化を考えないならば一旦ここで終了。
## 確認メッセージの日本語化
本登録していない場合に表示される画面は多言語化されている。
__() 部分の日本語訳を ja.json に追加するか、直接このファイルをいじって日本語化しておく。

```php:/resources/view/auth/verify.blade.php
 :
    <div class="card-header">{{ __('Verify Your Email Address') }}</div>
        <div class="card-body">
            @if (session('resent'))
                <div class="alert alert-success" role="alert">
                    {{ __('A fresh verification link has been sent to your email address.') }}
                </div>
            @endif

            {{ __('Before proceeding, please check your email for a verification link.') }}
            {{ __('If you did not receive the email') }} <a href="{{ route('verification.resend') }}">{{ __('click here to request another') }}</a>
:
```

## 確認メールの日本語化
先ずは大元のメールのテンプレートを修正する。これを使わず、直接 view を参照するならこの作業は不要。
vendorのテンプレを publish して、こんな感じに修正する。

```sh:
$ php artisan vendor:publish --tag=laravel-notifications
```

```php:/resources/views/vendor/notifications/email.blade.php
@component('mail::message')
{{-- Greeting --}}
@if (! empty($greeting))
# {{ $greeting }}
@else
@if ($level === 'error')
# @lang('Whoops!')
@else
<b>こんにちは</b>
@endif
@endif

{{-- Intro Lines --}}
@foreach ($introLines as $line)
{{ $line }}

@endforeach

{{-- Action Button --}}
@isset($actionText)
<?php
    switch ($level) {
        case 'success':
        case 'error':
            $color = $level;
            break;
        default:
            $color = 'primary';
    }
?>
@component('mail::button', ['url' => $actionUrl, 'color' => $color])
{{ $actionText }}
@endcomponent
@endisset

{{-- Outro Lines --}}
@foreach ($outroLines as $line)
{{ $line }}

@endforeach

{{-- Salutation --}}
@if (! empty($salutation))
{{ $salutation }}
@else
{{ config('app.name') }}
@endif

{{-- Subcopy --}}
@isset($actionText)
@slot('subcopy')
@lang(
":actionText ボタンが利用できない場合は、以下のURLをコピー＆ペーストしてブラウザから直接アクセスしてください。<br />\n" .
    '[:actionURL](:actionURL)',
    [
        'actionText' => $actionText,
        'actionURL' => $actionUrl,
    ]
)
@endslot
@endisset
@endcomponent
```

## 確認通知メールの日本語化
まずは通知クラスを生成して修正する。

```sh:
$ php artisan make:notification CustomVerifyEmail
```

```php:/app/Notifications/CustomVerifyEmail.php
+ use Illuminate\Auth\Notifications\VerifyEmail;
:
- class CustomVerifyEmail extends Notification
+ class CustomVerifyEmail extends VerifyEmail
{
    :
    public function toMail($notifiable) {
        return (new MailMessage)
            ->subject(__('Verify Your Email Address'))
            ->line(__('Please click the link below to verify your email address.'))
            ->action(__('Verify Email Address'), $this->verificationUrl($notifiable))
            ->line(__('If you did not create an account, no further action is required.'));
    }
```
## 確認通知メールを User に紐づける

```php:/app/User.php
+ use App\Notifications\CustomVerifyEmail;

class User extends Authenticatable implements MustVerifyEmailContract
{
    :
+    public function sendEmailVerificationNotification()
+    {
+        $this->notify(new CustomVerifyEmail());
+    }
```
## パスワードリセットメールの日本語化
まずは通知クラスを生成して修正する。

```sh:
$ php artisan make:notification CustomResetPassword
```

```php:/app/Notifications/CustomResetPassword.php
+ use Illuminate\Auth\Notifications\ResetPassword;
:
- class CustomResetPassword extends Notification
+ class CustomResetPassword extends ResetPassword
{
+   public $token;
:
    public function __construct($token)
    {
+       $this->token = $token;
    }
:
    public function toMail($notifiable)
    {
        return (new MailMessage)
-           ->line('The introduction to the notification.')
-           ->action('Notification Action', url('/'))
-           ->line('Thank you for using our application!');
+           ->subject(__('Reset Password'))
+           ->line(__('Click button below and reset password.'))
+           ->action(__('Reset password'), url(route('password.reset', $this->token, false)))
+           ->line(__('If you did not request a password reset, no further action is required.'));
:
    }
```
## パスワードリセットメールを User に紐づける

```php:/app/User.php
+ use App\Notifications\CustomResetPassword;

class User extends Authenticatable implements MustVerifyEmailContract
{
    :
+    public function sendPasswordResetNotification($token) {
+        $this->notify(new CustomResetPassword($token));
+    }
```

## ja.json 参考
```json:/resouces/lang/ja.json
{
    "Login":"ログイン",
    "E-Mail Address":"メールアドレス",
    "Password":"パスワード",
    "Remember Me":"ログイン状態を保存する",
    "Forgot Your Password?":"パスワードをお忘れですか ?",
    "Register":"登録",
    "Name":"お名前",
    "Confirm Password":"パスワード(確認用)",
    "Reset Password":"パスワードリセット",
    "Send Password Reset Link":"パスワードリセットリンク送信",
    "Logout":"ログアウト",

    "Verify Your Email Address":"ユーザ登録を完了してください",
    "A fresh verification link has been sent to your email address.":"新しいリンクをあなたのメールアドレスに送信しました。",
    "Before proceeding, please check your email for a verification link.":"メールに記載されているリンクをクリックして、登録手続きを完了してください。",
    "If you did not receive the email":"メールが届いていなければ、",
    "click here to request another":"こちらをクリックして再送信してください。",
    
    "Please click the link below to verify your email address.":"メールアドレスを確認するために下のリンクをクリックしてください。",
    "Verify Email Address":"メールアドレス確認",
    "If you did not create an account, no further action is required.":"心当たりがない場合は、本メッセージは破棄してください。",
    
    "Reset Password":"パスワードリセット",
    "Click button below and reset password.":"下のボタンをクリックしてパスワードを再設定してください。",
    "Reset password":"パスワードリセット",
    "If you did not request a password reset, no further action is required.":"心当たりがない場合は、本メッセージは破棄してください。"
}
```
## メール送信エラー
メール送信の設定が正しくないと以下の様なエラーが発生する。

```
Swift_TransportException with message 'Expected response code 250 but got code "530", with message "530 5.7.1 Authentication required
```

その場合は、GMail を使うなど工夫してみてください。
例えば .env でとか

```
MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=587
MAIL_USERNAME=あなたのGMailアドレス@gmail.com
MAIL_PASSWORD=パスワード
MAIL_ENCRYPTION=tls
MAIL_FROM_ADDRESS=あなたのGMailアドレス@gmail.com
MAIL_FROM_NAME=名前
```

参考：[Nekyo@Laravel関連](https://qiita.com/search?q=laravel+nekyo)