Laravel 9.x パスワードリセット

イントロダクション

ほとんどのWebアプリケーションは、ユーザーが忘れたパスワードをリセットする方法を提供します。Laravelでは、構築するすべてのアプリケーションでこれを手作業で再実装する必要はなく、パスワードリセットリンクを送信してパスワードを安全にリセットするための便利なサービスを提供しています。

Note: さっそく始めたいですか?Laravelアプリケーションスターターキットを新しいLaravelアプリケーションにインストールしてください。Laravelのスターターキットは、忘れたパスワードのリセットを含む、認証システム全体のスカフォールドの面倒を見ています。

モデルの準備

Laravelのパスワードリセット機能を使用する前に、アプリケーションのApp\Models\UserモデルでIlluminate\Notifications\Notifiableトレイトを使用する必要があります。通常、このトレイトは、新しいLaravelアプリケーションで作成されるデフォルトのApp\Models\Userモデルに最初から含まれています。

次に、App\Models\UserモデルがIlluminate\Contracts\Auth\CanResetPasswordコントラクトを実装していることを確認します。フレームワークに含まれているApp\Models\Userモデルは、最初からこのインターフェイスを実装しており、Illuminate\Auth\Passwords\CanResetPasswordトレイトを使用して、インターフェイスの実装に必要なメソッドを持っています。

データベース準備

アプリケーションのパスワードリセットトークンを保存するためのテーブルを作成する必要があります。このテーブルのマイグレーションはデフォルトのLaravelアプリケーションに含まれているため、データベースをマイグレーションするだけでこのテーブルを作成できます。

php artisan migrate

信頼するホストの設定

デフォルトでは、LaravelはHTTPリクエストのhostヘッダの内容に関係なく受信したすべてのリクエストにレスポンスします。さらに、Webリクエスト中にアプリケーションへの絶対URLを生成するときに、hostヘッダの値を使用します。

通常、NginxやApacheなどのウェブサーバは、与えられたホスト名にマッチするリクエストのみをアプリケーションに送信するように設定する必要があります。しかし、ウェブサーバを直接カスタマイズできず、Laravelに特定のホスト名にしか応答しないように指示する必要がある場合は、アプリケーションのミドルウェアであるApp\Http\Middleware\TrustHostsを有効にすることで、それが可能になります。これは、アプリケーションがパスワードリセット機能を提供している場合、特に重要です。

このミドルウェアについて詳しく知りたい方は、TrustHostsミドルウェアのドキュメントを参照してください。

ルート

ユーザーがパスワードをリセットできるようにするためのサポートを適切に実装するには、ルートをいくつか定義する必要があります。最初に、ユーザーが自分の電子メールアドレスを介してパスワードリセットリンクをリクエストできるようにするためのルートのペアが必要になります。2つ目は、ユーザーが電子メールで送られてきたパスワードリセットリンクにアクセスしてパスワードリセットフォームに記入した後、実際にパスワードをリセットするためのルートが必要になります。

パスワードリセットリンクの要求

パスワードリセットリンクリクエストフォーム

まず、パスワードリセットリンクをリクエストするために必要なルートを定義します。手始めに、パスワードリセットリンクリクエストフォームを使用してビューを返すルートを定義します。

Route::get('/forgot-password', function () {
    return view('auth.forgot-password');
})->middleware('guest')->name('password.request');

このルートによって返されるビューには、emailフィールドを含むフォームが必要です。これにより、ユーザーは特定の電子メールアドレスのパスワードリセットリンクをリクエストできます。

フォーム送信処理

次に、「パスワードを忘れた」ビューからのフォーム送信リクエストを処理するルートを定義します。このルートは、電子メールアドレスを検証し、対応するユーザーにパスワードリセットリクエストを送信する責任があります。

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Password;

Route::post('/forgot-password', function (Request $request) {
    $request->validate(['email' => 'required|email']);

    $status = Password::sendResetLink(
        $request->only('email')
    );

    return $status === Password::RESET_LINK_SENT
                ? back()->with(['status' => __($status)])
                : back()->withErrors(['email' => __($status)]);
})->middleware('guest')->name('password.email');

先に進む前に、このルートをさらに詳しく調べてみましょう。最初に、リクエストのemail属性が検証されます。次に、Laravelの組み込みの「パスワードブローカ」(Passwordファサードが返す)を使用して、パスワードリセットリンクをユーザーに送信します。パスワードブローカは、指定するフィールド(この場合はメールアドレス)でユーザーを取得し、Laravelの組み込み通知システムを介してユーザーにパスワードリセットリンクを送信します。

sendResetLinkメソッドは、"status"スラッグを返します。このステータスは、Laravelの多言語化ヘルパを使って翻訳でき、リクエストのステータスに関するユーザーフレンドリーなメッセージをユーザーへ表示可能にします。パスワードリセットステータスの翻訳は、アプリケーションのlang/{lang}/passwords.php言語ファイルで決まります。ステータスのスラッグに指定できる各項目は、passwords言語ファイル内にあります。

PasswordファサードのsendResetLinkメソッドを呼び出すときに、Laravelがアプリケーションのデータベースからユーザーレコードを取得する方法をどのように知っているのか疑問に思われるかもしれません。Laravelパスワードブローカは、認証システムの「ユーザープロバイダ」を利用してデータベースレコードを取得します。パスワードブローカが使用するユーザープロバイダは、config/auth.php設定ファイルのpasswords設定配列内で設定します。カスタムユーザープロバイダの作成の詳細については、認証ドキュメントを参照してください。

Note: パスワードのリセットを手作業で実装する場合は、ビューの内容とルートを自分で定義する必要があります。必要なすべての認証および検証ロジックを含むスカフォールドが必要な場合は、Laravelアプリケーションスターターキットを確認してください。

パスワードのリセット

パスワードリセットフォーム

次に、電子メールで送信されたパスワードリセットリンクをユーザーがクリックして新しいパスワードを入力したときに、実際にパスワードをリセットするために必要なルートを定義します。まず、ユーザーがパスワードのリセットリンクをクリックしたときに表示されるパスワードのリセットフォームを表示するルートを定義しましょう。このルートは、後でパスワードリセットリクエストを確認するために使用するtokenパラメータを受け取ります。

Route::get('/reset-password/{token}', function ($token) {
    return view('auth.reset-password', ['token' => $token]);
})->middleware('guest')->name('password.reset');

このルートが返すビューにより、emailフィールド、passwordフィールド、password_confirmationフィールド、および非表示のtokenフィールドを含むフォームを表示します。これにはルートが受け取る秘密の$tokenの値が含まれている必要があります。

フォーム送信処理

もちろん、パスワードリセットフォームの送信を実際に処理するためルートを定義する必要もあります。このルートは、受信リクエストのバリデーションとデータベース内のユーザーのパスワードの更新を担当します。

use Illuminate\Auth\Events\PasswordReset;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Password;
use Illuminate\Support\Str;

Route::post('/reset-password', function (Request $request) {
    $request->validate([
        'token' => 'required',
        'email' => 'required|email',
        'password' => 'required|min:8|confirmed',
    ]);

    $status = Password::reset(
        $request->only('email', 'password', 'password_confirmation', 'token'),
        function ($user, $password) {
            $user->forceFill([
                'password' => Hash::make($password)
            ])->setRememberToken(Str::random(60));

            $user->save();

            event(new PasswordReset($user));
        }
    );

    return $status === Password::PASSWORD_RESET
                ? redirect()->route('login')->with('status', __($status))
                : back()->withErrors(['email' => [__($status)]]);
})->middleware('guest')->name('password.update');

先に進む前に、このルートをさらに詳しく調べてみましょう。最初に、リクエストのtokenemail、およびpassword属性がバリデーションされます。次に、Laravelの組み込みの「パスワードブローカ」(Passwordファサードが返す)を使用して、パスワードリセットリクエストの資格情報を検証します。

パスワードブローカに与えられたトークン、電子メールアドレス、およびパスワードが有効である場合、resetメソッドに渡されたクロージャが呼び出されます。ユーザーインスタンスとパスワードリセットフォームに提供された平文テキストのパスワードを受け取るこのクロージャ内で、データベース内のユーザーのパスワードを更新します。

resetメソッドは、"status"スラッグを返します。このステータスは、Laravelの多言語化ヘルパを使い翻訳でき、リクエストのステータスに関する分かりやすいメッセージをユーザーへ表示可能にします。パスワードリセットステータスの翻訳内容は、アプリケーションのlang/{lang}/passwords.php言語ファイルにより、決まります。ステータスのスラッグに指定できる各項目は、passwords言語ファイル内にあります。

先に進む前に、Passwordファサードのresetメソッドを呼び出すときに、Laravelがアプリケーションのデータベースからユーザーレコードを取得する方法をどのように知っているのか疑問に思われるかもしれません。Laravelパスワードブローカーは、認証システムの「ユーザープロバイダ」を利用してデータベースレコードを取得します。パスワードブローカが使用するユーザープロバイダは、config/auth.php設定ファイルのpasswords設定配列内で設定しています。カスタムユーザープロバイダの作成の詳細については、認証ドキュメントを参照してください。

期限切れトークンの削除

期限が切れたパスワードリセットトークンは、データベース内にまだ存在します。しかし、これらのレコードは、auth:clear-resets Artisanコマンドで簡単に削除できます。

php artisan auth:clear-resets

この処理を自動化したい場合は、アプリケーションのスケジューラへの、当コマンド追加を検討してください。

$schedule->command('auth:clear-resets')->everyFifteenMinutes();

カスタマイズ

リセットリンクのカスタマイズ

ResetPassword通知クラスが提供するcreateUrlUsingメソッドを使用して、パスワードリセットリンクURLをカスタマイズできます。このメソッドは、通知を受信して​​いるユーザーインスタンスとパスワードリセットリンクトークンを受信するクロージャを受け入れます。通常、このメソッドは、App\Providers\AuthServiceProviderサービスプロバイダのbootメソッドから呼び出す必要があります。

use Illuminate\Auth\Notifications\ResetPassword;

/**
 * 全認証/認可サービスの登録
 *
 * @return void
 */
public function boot()
{
    $this->registerPolicies();

    ResetPassword::createUrlUsing(function ($user, string $token) {
        return 'https://example.com/reset-password?token='.$token;
    });
}

リセットメールカスタマイズ

パスワードリセットリンクをユーザーに送信するために使用する通知クラスは簡単に変更できます。それには、App\Models\UserモデルのsendPasswordResetNotificationメソッドをオーバーライドします。このメソッド内で、自分で作成した通知クラスを使用して通知を送信できます。パスワードリセット$tokenは、メソッドが受け取る最初の引数です。この$tokenを使用して、パスワードリセットURLを作成し、ユーザーに通知を送信します。

use App\Notifications\ResetPasswordNotification;

/**
 * パスワードリセット通知をユーザーに送信
 *
 * @param  string  $token
 * @return void
 */
public function sendPasswordResetNotification($token)
{
    $url = 'https://example.com/reset-password?token='.$token;

    $this->notify(new ResetPasswordNotification($url));
}

ドキュメント章別ページ

ヘッダー項目移動

注目:アイコン:ページ内リンク設置(リンクがないヘッダーへの移動では、リンクがある以前のヘッダーのハッシュをURLへ付加します。

移動

クリックで即時移動します。

設定

適用ボタンクリック後に、全項目まとめて適用されます。

カラーテーマ
和文指定 Pagination
和文指定 Scaffold
Largeスクリーン表示幅
インデント
本文フォント
コードフォント
フォント適用確認

フォントの指定フィールドから、フォーカスが外れると、当ブロックの内容に反映されます。EnglishのDisplayもPreviewしてください。

フォント設定時、表示に不具合が出た場合、当サイトのクッキーを削除してください。

バックスラッシュを含むインライン\Code\Blockの例です。

以下はコードブロックの例です。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * ユーザに関連する電話レコードを取得
     */
    public function phone()
    {
        return $this->hasOne('App\Phone');
    }
}

設定を保存する前に、表示が乱れないか必ず確認してください。CSSによるフォントファミリー指定の知識がない場合は、フォントを変更しないほうが良いでしょう。

キーボード・ショートカット

オープン操作

PDC

ページ(章)移動の左オフキャンバスオープン

HA

ヘッダー移動モーダルオープン

MS

移動/設定の右オフキャンバスオープン

ヘッダー移動

T

最初のヘッダーへ移動

E

最後のヘッダーへ移動

NJ

次ヘッダー(H2〜H4)へ移動

BK

前ヘッダー(H2〜H4)へ移動

その他

?

このヘルプページ表示
閉じる