[Laravel] Email Verification(メールアドレスの確認機能)の使い方とカスタマイズについて

先日のLaravel5.7のリリースで新しく追加されたEmail Verificationがとても便利ですので紹介します。


今までのLaravelでは、フレームワーク内に認証機能が実装されており、これを有効にすることで簡単にログイン機能等を利用することができました。

デフォルトの挙動では、ユーザーの新規作成(/registerページ)後にそのままログインが可能になるというフローでした。

認証付きのサービス等でよく見る、ユーザーの新規作成時に登録されたメールアドレスが正確かどうかを確認するフロー(本登録メール等)をはさみたい場合には、自前で実装するかサードパーティーのパッケージを利用する必要がありました。(josiasmontag/laravel-email-verificationl等)

メールアドレスが正確かどうかの確認は、サービス上でユーザーとのやりとりが発生する場合においてとても重要です。

この機能がついにLaravelで実装されました。

Email Verificationの利用方法

ドキュメントに書いてある通り、使い方はとても簡単です。

App\UserモデルへIlluminate\Contracts\Auth\MustVerifyEmailインターフェイスと、Illuminate\Auth\MustVerifyEmailトレイトを追加します。

<?php

namespace App;

use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmailContract;;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Auth\MustVerifyEmail;

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

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'name', 'email', 'password',
    ];

    /**
     * The attributes that should be hidden for arrays.
     *
     * @var array
     */
    protected $hidden = [
        'password', 'remember_token',
    ];
}

認証ルートの作成は今まで通りphp artisan make:authコマンドを実行し、routes/web.phpファイルに認証のためのルートが追加されます。

追加されたAuth::routes();に引数を渡すように変更します。

// 変更前
// Auth::routes();

// 変更後
Auth::routes(['verify' => true]);
Tips

Auth::routes()メソッド(AuthファサードでIlluminate\Routing\Routerクラスのauthメソッドが呼ばれる)の処理が以下のように変更されてメールアドレス確認用のルーティングが追加されています。

/**
 * Register the typical authentication routes for an application.
 *
 * @param  array  $options
 * @return void
 */
public function auth(array $options = [])
{
    // Authentication Routes...
    $this->get('login', 'Auth\LoginController@showLoginForm')->name('login');
    $this->post('login', 'Auth\LoginController@login');
    $this->post('logout', 'Auth\LoginController@logout')->name('logout');

    // Registration Routes...
    $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register');
    $this->post('register', 'Auth\RegisterController@register');

    // Password Reset Routes...
    $this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
    $this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
    $this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
    $this->post('password/reset', 'Auth\ResetPasswordController@reset')->name('password.update');

    // Email Verification Routes...
    if ($options['verify'] ?? false) {
        $this->emailVerification();
    }
}

後は認証が確認なルートのmiddlewareverifiedを指定するだけです。(すべての認証ルートに適用する場合にはauthミドルウェアをverifiedミドルウェアに置き換えるだけです)

Route::middleware(['verified'])
    ->group(function() {
        Route::get('example', function() {
            return 'Access';
        });
    });

Laravel 5.6からアップデートした際には以下の作業が必要です

新しくLaravel5.7をインストールした場合には不要ですが、それ以前のバージョンからアップデートを行った場合には下記作業を行ってください。

1. VerificationControllerapp/Http/Controllers/Auth/VerificationController.phpへ配置
2. app/Http/Kernel.php$routeMiddlewareIlluminate\Auth\Middleware\EnsureEmailIsVerifiedを追加
/**
 * The application's route middleware.
 *
 * These middleware may be assigned to groups or used individually.
 *
 * @var array
 */
protected $routeMiddleware = [
    'auth' => \App\Http\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'cache.headers' => \Illuminate\Http\Middleware\SetCacheHeaders::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'signed' => \Illuminate\Routing\Middleware\ValidateSignature::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
];
3. app/Providers/EventServiceProvider.phpIlluminate\Auth\Listeners\SendEmailVerificationNotificationイベントを追加
<?php

namespace App\Providers;

use Illuminate\Support\Facades\Event;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array
     */
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
    ];

    /**
     * Register any events for your application.
     *
     * @return void
     */
    public function boot()
    {
        parent::boot();

        //
    }
}

認証周りのイベントについてはこちらで説明しています。

4 database/migrations/2014_10_12_000000_create_users_table.phpemail_verified_atの追加

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class CreateUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('users');
    }
}

設定ができたら、/registerへアクセスして新規登録を行いましょう。

登録したメールアドレスへ認証メールが届きます。

laravel-email-verification_01

確認メールのカスタマイズ

確認メールの送信はIlluminate\Auth\Notifications\VerifyEmailクラスで行います。

標準では英語の文面ですが、メールの構文にはIlluminate\Translation\Translatorクラスが使用されているため、オリジナルの言語ファイルを設置することにより文面のカスタマイズが行えます。

以下のファイルをapp/resources/lang/ja.jsonとして保存してください。

{
  "Hello!": "こんにちは",
  "Verify Email Address": "メールアドレスの確認",
  "Please click the button below to verify your email address.": "以下をクリックして、メールアドレスの確認を行ってください。",
  "If you did not create an account, no further action is required.": "このメールの内容に身に覚えがない場合は、このまま破棄してください。",
  "Regards": "宜しくお願い致します",
  "If you’re having trouble clicking the \":actionText\" button, copy and paste the URL below\ninto your web browser: [:actionURL](:actionURL)": "\":actionText\" ボタンが機能しない場合は, こちらのURLをブラウザにコピーして貼り付けてください: [:actionURL](:actionURL)"
}

config/app.phplocalejaに指定している場合に、設定した日本語でメールが送られてきます。

laravel-email-verification_02

Tips

メールの送信そのものをオリジナルにカスタマイズする場合には、toMailUsing()メソッドで送信処理をコールバックで渡すことができます。

app/Providers/AppServiceProvider.php等でオリジナルのコールバックを指定しましょう。

<?php

namespace App\Providers;

use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Notifications\Messages\MailMessage;
use Illuminate\Support\Facades\URL;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        VerifyEmail::toMailUsing(function ($notifiable) {
            $verifyUrl = URL::temporarySignedRoute(
                'verification.verify', now()->addMinutes(60), ['id' => $notifiable->getKey()]
            );

            return (new MailMessage())
                ->subject('Your subject')
                ->line('Whatever you like')
                ->action('Verify it', $verifyUrl);
        });
    }

    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        //
    }
}
© Xzxzyzyz