【Laravel 5.7】新たにメールアドレスの確認機能(Email Verification)が追加。使い方と仕組みを紹介します。

Laravel

こんにちは、aiiro(@aiiro29)です。

Laravel5.7に新機能、ユーザーのメールアドレス確認機能が追加されました!

今回はLaravel5.7で追加された、ユーザー登録をした時に入力したメールアドレスを確認する機能(Email Verification)を紹介します。

Laravel - The PHP Framework For Web Artisans
Laravel is a PHP web application framework with expressive, elegant syntax. We’ve already laid the foundation — freeing you to create without sweating the small...

アプリケーションを開発していると、メールアドレスの確認がまだ済んでいないユーザーに対して、確認を促すようにメッセージを表示したいということがあります。

メールアドレスの確認機能Laravelでサポートされるようになったことで、自分たちで実装しなければならない処理を減らせそうです。

Laraveの使い勝手が一層向上することが期待できますね。

アプリケーションの開発を安全かつ楽にするためにも、Laravel5.7を使い始める前に、メールの確認機能の使い方と、その仕組みについて確認しておきたいと思います。

スポンサーリンク

使い方

Userモデルに MustVerifyEmail を追加する

App\User モデルで Illuminate\Contracts\Auth\MustVerifyEmail インターフェースを実装します。


use Illuminate\Contracts\Auth\MustVerifyEmail as MustVerifyEmail;

// (中略)

class User extends Authenticatable implements MustVerifyEmail
{
    use Notifiable;

    // ...

}

make:auth コマンドを実行する

make:authコマンドを実行して、認証関連のファイルを生成します。

メールアドレスが確認できていないユーザー向けに表示する画面のテンプレートも生成されます。

テンプレートは resources/views/auth/verify.blade.php に作成されます。


php artisan make:auth

ルーティングを設定する

web.phpAuth::routes(['verify' => true]); を設定します。

更に middleware('verified') を使用して、メールアドレスが確認済みの場合のみアクセスできるようにしたいルーティングを設定します。


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

Auth::routes(['verify' => true]);

Route::get('/home', 'HomeController@index')->name('home');

以上で準備は完了です。

動作確認

ユーザー登録をしたときに、usersテーブルに email_verified_at がnullのレコードが登録されていることを確認します。

メールアドレスが確認されていないままで verified ミドルウェアを設定したエンドポイントにアクセスすると、email/verify にリダイレクトされます。

このとき表示されているテンプレートが、 resources/views/auth/verify.blade.php です。

入力したメールアドレスにメールが送信されていますので、メール中のリンクをクリックします。

成功すると email_verified_at が更新されます。

メールアドレスの確認後は、ミドルウェアで制限しているエンドポイントにアクセスできるようになります。

メール確認機能の仕組み

使い方は以上ですが、Email Verificationがどういう仕組で動いているかを見ておきたいと思います。

MustVerifyEmailについて

App\Http\Kernel$routeMiddleware に設定があるので、そこから確認します。


class Kernel extends HttpKernel
{

// 中略

    protected $routeMiddleware = [

// 中略

        'verified' => \Illuminate\Auth\Middleware\EnsureEmailIsVerified::class,
    ];

Illuminate\Auth\Middleware\EnsureEmailIsVerified が使用されていることがわかりました。

それでは Illuminate\Auth\Middleware\EnsureEmailIsVerified の実装を見てみます。


class EnsureEmailIsVerified
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return \Illuminate\Http\Response
     */
    public function handle($request, Closure $next)
    {
        if (! $request->user() ||
            ($request->user() instanceof MustVerifyEmail &&
            ! $request->user()->hasVerifiedEmail())) {
            return Redirect::route('verification.notice');
        }

        return $next($request);
    }
}

EnsureEmailIsVerified はhandle()で userが MustVerifyEmail のインスタンスかどうかを判定し、
メールアドレスが未確認であればリダイレクトさせています。

“App\Userモデル”で”MustVefiryEmail”をimplementsしたのは、このためです。

また、上記のコードで使用されている”hasVerifiedEmail()”ですが、これは”Illuminate\Auth\MustVerifyEmail”トレイトで定義されています。

次は”Illuminate\Auth\MustVerifyEmail”トレイトをどうやって利用しているかを見ていきます。

Authenticatableについて

“Illuminate\Auth\MustVerifyEmail”トレイトをどうやって利用しているかを知るためには、”Illuminate\Foundation\Auth\User”を読むことになります。

理由は”Illuminate\Foundation\Auth\User”が”Illuminate\Foundation\Auth\User”は”Illuminate\Auth\MustVerifyEmail”トレイトを使用しているためです。

<?php

namespace Illuminate\Foundation\Auth;

use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;

class User extends Model implements
    AuthenticatableContract,
    AuthorizableContract,
    CanResetPasswordContract
{
    use Authenticatable, Authorizable, CanResetPassword, MustVerifyEmail;
}

そして”App\User”モデルは”Illuminate\Foundation\Auth\User”に“Authenticatable”というエイリアスを設定し、継承しています。

<?php

use Illuminate\Foundation\Auth\User as Authenticatable;

class User extends Authenticatable implements MustVerifyEmail
{
    // ...
}

“Illuminate\Foundation\Auth\User”はトレイトである”Illuminate\Auth\MustVerifyEmail”をuseしていますが、インターフェースである”Illuminate\Contracts\Auth\MustVerifyEmail”をimplementsしていません。

そのため、”App\Userモデル”でインターフェースを実装する必要があったのです。

登録されたメールアドレスにメールを送信する仕組み

ユーザー登録時に入力されたメールアドレスに、メールを送信する処理について、確認したいと思います。

config/app.php でサービスプロバイダーとして App\Providers\EventServiceProvider::class が登録されているので、中身を見てみましょう。


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();

        //
    }
}

EventServiceProviderでは$listenSendEmailVerificationNotification が設定されています。

SendEmailVerificationNotification を読んでみると、 Illuminate\Auth\Listeners 配下のリスナーであることがわかります。


class SendEmailVerificationNotification
{
    /**
     * Handle the event.
     *
     * @param  \Illuminate\Auth\Events\Registered  $event
     * @return void
     */
    public function handle(Registered $event)
    {
        if ($event->user instanceof MustVerifyEmail) {
            $event->user->sendEmailVerificationNotification();
        }
    }
}

SendEmailVerificationNotification ではuserが MustVefiryEmail のインスタンスかどうかを判定し、 sendEmailVerificationNotification() を使ってNotificationを送信しています。

まとめ

Laravel5.7で追加されたメールアドレスの確認機能の使い方と仕組みについて紹介しました。

メールアドレスの検証機能は多くのアプリケーションで実装されている機能ですが、LaravelのEmail Verificationを使用することで、自分たちで実装するコードをグッと減らすことができるようになっています。

以上の内容が、メールアドレスの確認機能を使ってみようと思っている方にとって、参考になれば幸いです。