Laravel入門トップページ


目次

  1. Composerのダウンロードとインストール
  2. コメント掲示板を作成してみよう
  3. リレーションシップを使いこなそう
  4. ユーザ認証の機能を実現しよう
    1. 概要と準備
    2. メールの設定
    3. 認証機能の実装
    4. 学籍番号の登録とログイン名
    5. 登録メールアドレスの認証
    6. パスワードのリセット
    7. プロフィールの表示
    8. パスワードの変更
  5. マルチ認証の機能を実現しよう
  6. MongoDB に接続しよう
  7. キューを利用しよう
  8. コマンド(コンソール)を利用しよう
  9. 本番環境にデプロイしよう

ユーザ認証の機能を実現しよう

登録メールアドレスの認証

ここまでの作業では,架空のメールアドレスでも登録ができてしまう.ここでは,ユーザが登録したときにメールが届き,受信したユーザがリンクをクリックして初めて登録が完了するようにしたい.

目次に戻る

users テーブルに項目を追加する

データベースのマイグレーションファイルを変更して,2つの列を追加する.

database/migrations/2014_10_12_000000_create_users_table.php
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('email')->unique();
            $table->integer('student_id')->unique();
            $table->string('login_id')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->string('email_token')->nullable();
            $table->tinyInteger('verified')->default(0);
            $table->timestamps();
        });
    }

ジョブの待ち行列に関するテーブルも作成する.

[GakuinHana@rin06 laravelUser]$ php artisan queue:table ⏎
Migration created successfully!
[GakuinHana@rin06 laravelUser]$ php artisan queue:failed-table ⏎
Migration created successfully!
[GakuinHana@rin06 laravelUser]$

目次に戻る

モデルの編集

ユーザが登録変更をできるように,モデルの $fillable に追加する.

app/User.php (抜粋)
    protected $fillable = [
        'name', 'email', 'password',
        'student_id', 'login_id',
        'email_token', 'verified',
    ];

目次に戻る

メール認証クラスを作成する

artisan コマンドでメール認証クラスを作成する.

[GakuinHana@rin06 laravelUser]$ php artisan make:mail EmailVerification ⏎
Mail created successfully.
[GakuinHana@rin06 laravelUser]$

上のコマンドを実行すると,app/Mail ディレクトリが作成され,その中に EmailVerification.php の雛形が作成された.

app/Mail/EmailVerification.php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;

class EmailVerification extends Mailable
{
    use Queueable, SerializesModels;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
        return $this->view('view.name');
    }
}

上の EmailVerification.php を編集して,ユーザモデルを追加する.

app/Mail/EmailVerification.php
<?php

namespace App\Mail;

use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Contracts\Queue\ShouldQueue;
use App\User;

class EmailVerification extends Mailable
{
    use Queueable, SerializesModels;
    public $user;

    /**
     * Create a new message instance.
     *
     * @return void
     */
    public function __construct(User $user)
    {
        $this->user = $user;
    }

    /**
     * Build the message.
     *
     * @return $this
     */
    public function build()
    {
      return $this->view('email.email')
                  ->with([
                    'email_token' => $this->user->email_token
                  ]);
    }
}

目次に戻る

メールの本文を作る

resources/views/ に email というフォルダを作成し email.blade.php を作る.

resources/views/email/email.blade.php
<h1>Click the Link To Verify Your Email</h1>

<p>あなたのメールアドレスを検証するために次のリンクをクリックしてください.<br>
{{url('/auth/verifyemail/'.$email_token)}} </p>

<p>心当たりが無い場合は無視してください.</p>

目次に戻る

メール送信のキュージョブを作成する

artisan コマンドで新たな queue job 作成する.なお,キューの詳細はこちらで確認できる.

[GakuinHana@rin06 laravelUser]$ php artisan make:job SendVerificationEmail ⏎
Job created successfully.
[GakuinHana@rin06 laravelUser]$

上のコマンドで app/ ディレクトリ内に Jobs ディレクトリが作成され,この中に SendVerificationEmail.php ファイルが生成された.

app/Jobs/SendVerificationEmail.php
<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

class SendVerificationEmail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct()
    {
        //
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        //
    }
}

このファイルを次のように編集する.

app/Jobs/SendVerificationEmail.php
<?php

namespace App\Jobs;

use Illuminate\Bus\Queueable;
use Illuminate\Queue\SerializesModels;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;

use Mail;
use App\Mail\EmailVerification;

class SendVerificationEmail implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;

    protected $user;

    /**
     * Create a new job instance.
     *
     * @return void
     */
    public function __construct($user)
    {
        $this->user = $user;
    }

    /**
     * Execute the job.
     *
     * @return void
     */
    public function handle()
    {
        $email = new EmailVerification($this->user);
        Mail::to($this->user->email)->send($email);
    }
}

目次に戻る

コントローラを編集

コントローラを次のように編集する.

app/Http/Controllers/Auth/RegisterController.php
<?php

namespace App\Http\Controllers\Auth;

use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use App\Jobs\SendVerificationEmail;

class RegisterController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Register Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles the registration of new users as well as their
    | validation and creation. By default this controller uses a trait to
    | provide this functionality without requiring any additional code.
    |
    */

    use RegistersUsers;

    /**
     * Where to redirect users after registration.
     *
     * @var string
     */
    protected $redirectTo = '/home';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest');
    }

    /**
     * Get a validator for an incoming registration request.
     *
     * @param  array  $data
     * @return \Illuminate\Contracts\Validation\Validator
     */
    protected function validator(array $data)
    {
        return Validator::make($data, [
            'name' => 'required|string|max:255',
            'email' => 'required|string|email|max:255|unique:users',
            'password' => 'required|string|min:6|confirmed',
            'student_id' => 'required|integer|min:6100000|max:6199999|unique:users',
            'login_id' => 'required|string|min:1|max:255|unique:users',
        ]);
    }

    /**
     * Create a new user instance after a valid registration.
     *
     * @param  array  $data
     * @return \App\User
     */
    protected function create(array $data)
    {
        return User::create([
            'name' => $data['name'],
            'email' => $data['email'],
            'password' => bcrypt($data['password']),
            'student_id' => $data['student_id'],
            'login_id' => $data['login_id'],
            'email_token' => base64_encode($data['email']),
        ]);
    }

    /**
    *  Handle a registration request for the application.
    *
    * @param \Illuminate\Http\Request $request
    * @return \Illuminate\Http\Response
    */
    public function register(Request $request)
    {
      $this->validator($request->all())->validate();
      event(new Registered($user = $this->create($request->all())));
      dispatch(new SendVerificationEmail($user));
      return view('auth.verification');
    }

    /**
    *  Handle a registration request for the application.
    *
    * @param $token
    * @return \Illuminate\Http\Response
    */
    public function verify($token)
    {
      $user = User::where('email_token',$token)->first();
      $user->verified = 1;
      if($user->save()) {
        return view('auth.emailconfirm',['user'=>$user]);
      }
    }
}

目次に戻る

ビューの作成

ユーザ登録後に「メールをお送りしました」という画面を表示したいので,そのページのビューを作る.

resources/views/auth/verification.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
              <h1>ユーザ登録</h1>
              <p>ユーザ登録を行いました.</p>
              <p>確認のためにEメールを送信しましたので,メールのリンクをクリックしてください.</a></p>
            </div>
        </div>
    </div>
</div>
@endsection

さらに,メールのリンクをクリックして検証が終わったあとに表示されるページのビューを作る.

resources/views/auth/emailconfirm.blade.php
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
              <h1>メールアドレスが確認できました</h1>
              <p>あなたのメールアドレスが確認できました.</p>
              <p><a href="{{url('/login')}}">ここからログインしてください.</a></p>
            </div>
        </div>
    </div>
</div>
@endsection

目次に戻る

ルートを定義する

メールのリンクをクリックしたときに渡される /auth/verifyemail へのルートを定義する.

routes/web.php (抜粋)
Route::get('/', function () {
    return view('welcome');
});

Route::get('/auth/verifyemail/{token}', 'Auth\RegisterController@verify');

Auth::routes();

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

目次に戻る

データベースのリセット

ステップの最初にマイグレーションファイルを編集して,テーブルのスキーマを変更したので,データベースをリセットしておく.

[GakuinHana@rin06 laravelUser]$ php artisan migrate:rollback; php artisan migrate; php artisan db:seed ⏎

目次に戻る

実験してみよう

メールによる検証ができるようになったので,実際に実験してみよう.まずは,データベースのリセットをしておく.

[GakuinHana@rin06 laravelUser]$ php artisan migrate:rollback; php artisan migrate; php artisan db:seed ⏎

トップページから REGISTER へのリンクをクリックする.E-Mail Address には正しい(自分で受信可能な)メールアドレスを入力する.その他は適当な値でよい.

user-11

上で Register ボタンを押すと,次のような画面になる.

user-12

メールを確認して,リンクをクリックする.

user-13

メールのリンクをクリックすると,次の画面になり,認証された.

user-14

実際にログインIDでログインしてみる.

user-15

うまくログインできました.一見うまく行ったようです.

user-16

目次に戻る

動作の詳細を確認してみる

これまでの作業で,一見するとうまくメールでの認証ができたように思われます.しかしながら,まだ問題点がいくつか残っているので,その問題点を確認してみよう.

目次に戻る

データベースの確認

一旦,データベースをリセットしてから,Webから登録作業を行います.その途中で sqlite でデータベースの内容を確認します.

[GakuinHana@rin06 laravelUser]$ php artisan migrate:rollback; php artisan migrate; php artisan db:seed ⏎
Rolling back: 2018_07_01_163336_create_failed_jobs_table

... (中略) ...

Seeding: UsersTableSeeder
[GakuinHana@rin06 laravelUser]$ sqlite3 database/database.sqlite ⏎
SQLite version 3.6.20
Enter ".help" for instructions
Enter SQL statements terminated with a ";"
sqlite> select * from users; ⏎ ## ユーザ登録前
1|A. Sample|a@sample.com|6101701|user_a|$2y$10$oJVKp5XFGUD8i5XfhECqIeGyJphruzEL/2fT5qdWwULpEgrCvA.Y.|||0|2018-07-01 17:47:26|2018-07-01 17:47:26
2|B. Sample|b@sample.com|6101702|user_b|$2y$10$.OnT/mPj9wtgBPf51AAQJOJZK7N6vxcp67oYNUyalOjwOpnVKVSy6|||0|2018-07-01 17:47:26|2018-07-01 17:47:26
3|C. Sample|c@sample.com|6101703|user_c|$2y$10$mqSsPThslJJaMZxjZs9CuurLJmjH6UV826g5tYfcuVfpLnfWJLrhS|||0|2018-07-01 17:47:26|2018-07-01 17:47:26
sqlite> select * from users; ⏎  ## ユーザ登録後(メール送信後)
1|A. Sample|a@sample.com|6101701|user_a|$2y$10$oJVKp5XFGUD8i5XfhECqIeGyJphruzEL/2fT5qdWwULpEgrCvA.Y.|||0|2018-07-01 17:47:26|2018-07-01 17:47:26
2|B. Sample|b@sample.com|6101702|user_b|$2y$10$.OnT/mPj9wtgBPf51AAQJOJZK7N6vxcp67oYNUyalOjwOpnVKVSy6|||0|2018-07-01 17:47:26|2018-07-01 17:47:26
3|C. Sample|c@sample.com|6101703|user_c|$2y$10$mqSsPThslJJaMZxjZs9CuurLJmjH6UV826g5tYfcuVfpLnfWJLrhS|||0|2018-07-01 17:47:26|2018-07-01 17:47:26
4|Koichiro Rinsaka|rinsaka@sample.com|6120001|rinsaka|$2y$10$RghjYqdp545rdc4fmlSKxu1YHrTsGKkRMdSipGVykJx6J/aE1Myny||a29pY2hpcm8ucmluc2FrYUBnbWFpbC5jb20=|0|2018-07-01 17:49:10|2018-07-01 17:49:10
sqlite> select * from users; ⏎ ## メールのリンクをクリックしたあと
1|A. Sample|a@sample.com|6101701|user_a|$2y$10$oJVKp5XFGUD8i5XfhECqIeGyJphruzEL/2fT5qdWwULpEgrCvA.Y.|||0|2018-07-01 17:47:26|2018-07-01 17:47:26
2|B. Sample|b@sample.com|6101702|user_b|$2y$10$.OnT/mPj9wtgBPf51AAQJOJZK7N6vxcp67oYNUyalOjwOpnVKVSy6|||0|2018-07-01 17:47:26|2018-07-01 17:47:26
3|C. Sample|c@sample.com|6101703|user_c|$2y$10$mqSsPThslJJaMZxjZs9CuurLJmjH6UV826g5tYfcuVfpLnfWJLrhS|||0|2018-07-01 17:47:26|2018-07-01 17:47:26
4|Koichiro Rinsaka|rinsaka@sample.com|6120001|rinsaka|$2y$10$RghjYqdp545rdc4fmlSKxu1YHrTsGKkRMdSipGVykJx6J/aE1Myny|GeFRoIaNJFJDahRUGgp7wrULEYmui23Nn0Tmqzqyz7k3gudPLSOe8FfmAYBn|a29pY2hpcm8ucmluc2FrYUBnbWFpbC5jb20=|1|2018-07-01 17:49:10|2018-07-01 17:50:10
sqlite> .exit ⏎
[GakuinHana@rin06 laravelUser]$

上の結果のとおり,メールのリンクをクリックして初めてテーブルの9列目 verified 属性の値が 1 になる.本来なら verified の値が 1 になるまで(つまり,メールアドレスの確認が終わるまで),ログインできないようにすべきでしょう.

目次に戻る

メールアドレス確認前にログインしてみる

まず,データベースをリセットして,実験してみよう.実際に,ユーザ登録をした直後にログインができており,メールのリンクをクリックする前に,ログアウト,再度ログインの作業をしてみよう.やはりログインできてしまうのは問題でしょう.

目次に戻る

メールアドレスを確認するまではログイン出来ないように

ここで,メールアドレスの確認をするまで(つまりverified の値が1になるまで),ログインできないようにしよう.

app/Http/Controllers/Auth/LoginController.php を編集する.ログインが成功した直後に authenticated() 関数が呼ばれるが,これは vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php に定義されている.この authenticated() をオーバーライドするために,app/Http/Controllers/Auth/LoginController.php に記述する.(vendor/ 以下にある AuthenticatesUsers.php を直接編集するわけではないことに注意しよう.)

app/Http/Controllers/Auth/LoginController.php
<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;

class LoginController extends Controller
{
    /*
    |--------------------------------------------------------------------------
    | Login Controller
    |--------------------------------------------------------------------------
    |
    | This controller handles authenticating users for the application and
    | redirecting them to your home screen. The controller uses a trait
    | to conveniently provide its functionality to your applications.
    |
    */

    use AuthenticatesUsers;

    /**
     * Where to redirect users after login.
     *
     * @var string
     */
    protected $redirectTo = '/home';

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    /**
     * The user has been authenticated.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  mixed  $user
     * @return mixed
     */
    protected function authenticated(Request $request, $user)
    {
        // ログイン後にここが呼び出される
        // メールでの認証が済んでいるかをチェックする
        if(!$user->verified) {
          // メールでの認証が済んでいないので強制ログアウト
          $this->guard()->logout();
          $request->session()->invalidate();
          return redirect('/login')->with('warning', 'メールの確認をしてください');
        }
    }

    public function username()
    {
      return 'login_id';
    }
}

トップページ (welcome.blade.php) にフラッシュメッセージを表示するようにする.

resources/views/welcome.blade.php (抜粋)
    <body>
        {{-- フラッシュメッセージの表示 --}}
        @if (session('warning'))
            <div class="alert alert-warning">
                {{ session('warning') }}
            </div>
        @endif
        @if (session('status'))
            <div class="alert alert-info">
                {{ session('status') }}
            </div>
        @endif
        <div class="flex-center position-ref full-height">
            @if (Route::has('login'))
                <div class="top-right links">
                    @if (Auth::check())
                        <a href="{{ url('/home') }}">Home</a>
                    @else
                        <a href="{{ url('/login') }}">Login</a>
                        <a href="{{ url('/register') }}">Register</a>
                    @endif
                </div>
            @endif

            <div class="content">
                <div class="title m-b-md">
                    Laravel
                </div>

                <div class="links">
                    <a href="https://laravel.com/docs">Documentation</a>
                    <a href="https://laracasts.com">Laracasts</a>
                    <a href="https://laravel-news.com">News</a>
                    <a href="https://forge.laravel.com">Forge</a>
                    <a href="https://github.com/laravel/laravel">GitHub</a>
                </div>
            </div>
        </div>
    </body>

ログインページにもフラッシュメッセージを表示するようにする.

resources/views/auth/login.blade.php (抜粋)
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Login</div>

                <div class="panel-body">
                    {{-- フラッシュメッセージの表示 --}}
                    @if (session('warning'))
                        <div class="alert alert-warning">
                            {{ session('warning') }}
                        </div>
                    @endif
                    @if (session('status'))
                        <div class="alert alert-info">
                            {{ session('status') }}
                        </div>
                    @endif
                    <form class="form-horizontal" method="POST" action="{{ route('login') }}">
                        {{ csrf_field() }}

テスト用のユーザでもログインできるように,シーダーを変更しておく.(たとえば,user_c だけ変更せずにどのような動作になるか検証するとよい.)

database/seeds/UsersTableSeeder.php
    public function run()
    {
        DB::table('users')->delete();

        User::create([
          'name' => 'A. Sample',
          'email' => 'a@sample.com',
          'student_id' => 6101701,
          'login_id' => 'user_a',
          'password' => bcrypt('abc'),
          'verified' => 1,
          'created_at' => Carbon::now()
        ]);

        User::create([
          'name' => 'B. Sample',
          'email' => 'b@sample.com',
          'student_id' => 6101702,
          'login_id' => 'user_b',
          'password' => bcrypt('abc'),
          'verified' => 1,
          'created_at' => Carbon::now()
        ]);

        User::create([
          'name' => 'C. Sample',
          'email' => 'c@sample.com',
          'student_id' => 6101703,
          'login_id' => 'user_c',
          'password' => bcrypt('abc'),
          'verified' => 0,
          'created_at' => Carbon::now()
        ]);
    }

実際にデータベースをリセットしてから,実験してみよう.新規ユーザ (rinsaka) や user_c でログインすると強制的にログアウトになり,フラッシュメッセージが表示されます.

user-17

強制的にログアウトされ,フラッシュメッセージが表示された.フラッシュメッセージのスタイルはこのあたりを参考に設定すれば良い.

user-18

目次に戻る

メールリンクの有効期限

このあとは確認メールの有効期限の設定と確認メールの再送信を実現しよう.

目次に戻る

マイグレーションファイルの編集

users テーブルに登録メールを送信した日時を記録するための属性を追加する.

database/migrations/2014_10_12_000000_create_users_table.php (抜粋)
<?php

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

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->integer('student_id')->unique();
            $table->string('login_id')->unique();
            $table->string('password');
            $table->rememberToken();
            $table->string('email_token')->nullable();
            $table->tinyInteger('verified')->default(0);
            $table->timestamp('sent_at')->default(Carbon::now());
            $table->timestamps();
        });
    }

データベースをリセットしておく.

[GakuinHana@rin06 laravelUser]$ php artisan migrate:rollback; php artisan migrate; php artisan db:seed ⏎
Rolling back: 2018_07_01_163336_create_failed_jobs_table
Rolled back:  2018_07_01_163336_create_failed_jobs_table
Rolling back: 2018_07_01_163318_create_jobs_table
Rolled back:  2018_07_01_163318_create_jobs_table
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back:  2014_10_12_100000_create_password_resets_table
Rolling back: 2014_10_12_000000_create_users_table
Rolled back:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table
Migrating: 2018_07_01_163318_create_jobs_table
Migrated:  2018_07_01_163318_create_jobs_table
Migrating: 2018_07_01_163336_create_failed_jobs_table
Migrated:  2018_07_01_163336_create_failed_jobs_table
Seeding: UsersTableSeeder
[GakuinHana@rin06 laravelUser]$

目次に戻る

リンクの有効期限を検証する

app/Http/Controllers/Auth/RegisterController.php の verify() 関数を修正し,確認メールのリンクがリクエストされたときに経過時間を検証するようにする.

app/Http/Controllers/Auth/RegisterController.php (抜粋)
<?php

namespace App\Http\Controllers\Auth;

use App\User;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Validator;
use Illuminate\Foundation\Auth\RegistersUsers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Http\Request;
use App\Jobs\SendVerificationEmail;
use Carbon\Carbon;

class RegisterController extends Controller
{

... (中略) ...

  public function verify($token)
  {
    $user = User::where('email_token',$token)->first();
    // 現在の時刻を取得
    $date_now = new Carbon(Carbon::now());
    // メールの送信時刻を取得し,1時間加えた時刻を有効期限とする
    $date_expire = Carbon::createFromFormat('Y-m-d H:i:s', $user->sent_at);
    $date_expire->addHour();

    // リンクの有効期限のチェック
    if ($date_now->gt($date_expire)) {  // gt は Grater Than,つまり "より大きい"
      return redirect('/')
              ->with('warning', 'メールリンクの有効期限(1時間)を過ぎました');
    }

    $user->verified = 1;
    if($user->save()) {
      return view('auth.emailconfirm',['user'=>$user]);
    }
  }
}

メールの送信から1時間以上経過した段階でメールのリンクをクリックすると次のような画面になる(1時間待つのが面倒であれば,上の26行目をコメントアウトすると良い).また1時間以内の場合にはメールアドレスの検証ができることも確認しておこう.

user-19

目次に戻る

認証メールの再送信

メールリンクの有効期限が設定できたので,期限が切れた場合やメールが届かなかった場合に認証メールを再送信できるようにする.

目次に戻る

ルートを定義する

routes/web.php にルートを記述する.この中の Auth::routes(); という記述によって認証に必要なルートがまとめて定義される.この定義を artisan コマンドで確認する.

[GakuinHana@rin06 laravelUser]$ php artisan route:list ⏎
+--------+----------+--------------------------+------------------+------------------------------------------------------------------------+--------------+
| Domain | Method   | URI                      | Name             | Action                                                                 | Middleware   |
+--------+----------+--------------------------+------------------+------------------------------------------------------------------------+--------------+
|        | GET|HEAD | /                        |                  | Closure                                                                | web          |
|        | GET|HEAD | api/user                 |                  | Closure                                                                | api,auth:api |
|        | GET|HEAD | auth/verifyemail/{token} |                  | App\Http\Controllers\Auth\RegisterController@verify                    | web,guest    |
|        | GET|HEAD | home                     | home             | App\Http\Controllers\HomeController@index                              | web,auth     |
|        | POST     | login                    |                  | App\Http\Controllers\Auth\LoginController@login                        | web,guest    |
|        | GET|HEAD | login                    | login            | App\Http\Controllers\Auth\LoginController@showLoginForm                | web,guest    |
|        | POST     | logout                   | logout           | App\Http\Controllers\Auth\LoginController@logout                       | web          |
|        | POST     | password/email           | password.email   | App\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail  | web,guest    |
|        | GET|HEAD | password/reset           | password.request | App\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm | web,guest    |
|        | POST     | password/reset           |                  | App\Http\Controllers\Auth\ResetPasswordController@reset                | web,guest    |
|        | GET|HEAD | password/reset/{token}   | password.reset   | App\Http\Controllers\Auth\ResetPasswordController@showResetForm        | web,guest    |
|        | GET|HEAD | register                 | register         | App\Http\Controllers\Auth\RegisterController@showRegistrationForm      | web,guest    |
|        | POST     | register                 |                  | App\Http\Controllers\Auth\RegisterController@register                  | web,guest    |
|        | GET|HEAD | users/{id}               |                  | App\Http\Controllers\UsersController@show                              | web,auth     |
+--------+----------+--------------------------+------------------+------------------------------------------------------------------------+--------------+
[GakuinHana@rin06 laravelUser]$

上の定義を参考に routes/web.php に定義を追加する.

routes/web.php (抜粋)
Route::get('/', function () {
    return view('welcome');
});

Route::get('/auth/verifyemail/{token}', 'Auth\RegisterController@verify');

Auth::routes();
Route::get('/resend', 'Auth\RegisterController@showReSendForm')->name('resend');
Route::post('/resend', 'Auth\RegisterController@reSend');

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

Route::get('/users/{id}', 'UsersController@show');

定義ができたらルートを再度確認する.

[GakuinHana@rin06 laravelUser]$ php artisan route:list ⏎
+--------+----------+--------------------------+------------------+------------------------------------------------------------------------+--------------+
| Domain | Method   | URI                      | Name             | Action                                                                 | Middleware   |
+--------+----------+--------------------------+------------------+------------------------------------------------------------------------+--------------+
|        | GET|HEAD | /                        |                  | Closure                                                                | web          |
|        | GET|HEAD | api/user                 |                  | Closure                                                                | api,auth:api |
|        | GET|HEAD | auth/verifyemail/{token} |                  | App\Http\Controllers\Auth\RegisterController@verify                    | web,guest    |
|        | GET|HEAD | home                     | home             | App\Http\Controllers\HomeController@index                              | web,auth     |
|        | POST     | login                    |                  | App\Http\Controllers\Auth\LoginController@login                        | web,guest    |
|        | GET|HEAD | login                    | login            | App\Http\Controllers\Auth\LoginController@showLoginForm                | web,guest    |
|        | POST     | logout                   | logout           | App\Http\Controllers\Auth\LoginController@logout                       | web          |
|        | POST     | password/email           | password.email   | App\Http\Controllers\Auth\ForgotPasswordController@sendResetLinkEmail  | web,guest    |
|        | GET|HEAD | password/reset           | password.request | App\Http\Controllers\Auth\ForgotPasswordController@showLinkRequestForm | web,guest    |
|        | POST     | password/reset           |                  | App\Http\Controllers\Auth\ResetPasswordController@reset                | web,guest    |
|        | GET|HEAD | password/reset/{token}   | password.reset   | App\Http\Controllers\Auth\ResetPasswordController@showResetForm        | web,guest    |
|        | POST     | register                 |                  | App\Http\Controllers\Auth\RegisterController@register                  | web,guest    |
|        | GET|HEAD | register                 | register         | App\Http\Controllers\Auth\RegisterController@showRegistrationForm      | web,guest    |
|        | POST     | resend                   |                  | App\Http\Controllers\Auth\RegisterController@reSend                    | web,guest    |
|        | GET|HEAD | resend                   | resend           | App\Http\Controllers\Auth\RegisterController@showReSendForm            | web,guest    |
|        | GET|HEAD | users/{id}               |                  | App\Http\Controllers\UsersController@show                              | web,auth     |
+--------+----------+--------------------------+------------------+------------------------------------------------------------------------+--------------+
[GakuinHana@rin06 laravelUser]$

目次に戻る

Register ページにメール再送信ページへのリンクを設置する.

resources/views/auth/register.blade.php (抜粋)
                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    Register
                                </button>
                            </div>
                        </div>
                    </form>
                    <p><a href="{{ route('resend') }}">Send register link again</a></p>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

目次に戻る

コントローラを編集

コントローラに2つの関数を追加する.

app/Http/Controllers/Auth/RegisterController.php (抜粋)
    public function register(Request $request)
    {
      $this->validator($request->all())->validate();
      event(new Registered($user = $this->create($request->all())));
      dispatch(new SendVerificationEmail($user));
      return view('auth.verification');
    }

    public function showReSendForm()
    {
      dd("showReSendForm");
    }

    public function reSend(Request $request)
    {
      dd($request);
    }

目次に戻る

リンクの確認

Webサーバを再起動して,/register からリンクを表示してみる.

user-20

再送信ページの表示

コントローラからビューを呼び出す.

app/Http/Controllers/Auth/RegisterController.php (抜粋)
    public function showReSendForm()
    {
      return view('auth.resend');
    }

ビューを作る.なお,register.blade.php をコピーして編集する(メールアドレスの入力ボックスだけ残し,呼び出し先の変更をする)と良い.

resources/views/auth/resend.blade.php (抜粋)
@extends('layouts.app')

@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Send register mail link again</div>

                <div class="panel-body">
                    {{-- フラッシュメッセージの表示 --}}
                    @if (session('warning'))
                        <div class="alert alert-warning">
                            {{ session('warning') }}
                        </div>
                    @endif
                    @if (session('status'))
                        <div class="alert alert-info">
                            {{ session('status') }}
                        </div>
                    @endif
                    <form class="form-horizontal" method="POST" action="{{ route('resend') }}">
                        {{ csrf_field() }}

                        <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                            <label for="email" class="col-md-4 control-label">E-Mail Address</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required>

                                @if ($errors->has('email'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    Send Again
                                </button>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

目次に戻る

再送信ボタンを押してみる

再送信のリンクをクリックして,適当なメールアドレスを入力する.最後に「Send Again」ボタンをクリックする.

user-21

メールアドレスを取得できていることが確認できる.

user-22

目次に戻る

メールを再送信する

メールの再送信処理を記述しよう.ただし,まだ登録されていないアドレスやすでに検証が済んでいるアドレスに送信しても意味がないので,そのようなチェックは予め行っておく.

app/Http/Controllers/Auth/RegisterController.php (抜粋)
    public function reSend(Request $request)
    {
      $user = User::where('email', $request->email)->first();
      if (!$user) {
        return redirect('/resend')
                ->with('warning', '登録されていないアドレスです');
      }
      if ($user->verified == 1) {
        return redirect('/resend')
                ->with('warning', 'すでに検証されています.ログイン画面からログインしてください');
      }
      // メールの送信時間を現在時刻に変更
      $user->sent_at = Carbon::now();
      $user->save();
      // メールの送信ジョブを作成し,キューに投入する
      event(new Registered($user));
      dispatch(new SendVerificationEmail($user));
      return view('auth.verification');
    }

記述できたら,実際にメールの再送信を行い,リンクのクリックで検証できるかどうかを確かめよう.

目次に戻る