メインコンテンツまでスキップ

パスワードのリセット

はじめに

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

注記

すぐに始めたいですか?新しい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のデフォルトの 0001_01_01_000000_create_users_table.php データベースマイグレーションに含まれています。

信頼されたホストの設定

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

通常、特定のホスト名に一致するリクエストのみをアプリケーションに送信するように、NginxやApacheなどのWebサーバーを設定する必要があります。ただし、Webサーバーを直接カスタマイズする機能がなく、Laravelに特定のホスト名にのみ応答するように指示する必要がある場合は、アプリケーションのbootstrap/app.phpファイルでtrustHostsミドルウェアメソッドを使用することができます。これは、アプリケーションがパスワードリセット機能を提供している場合に特に重要です。

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

ルーティング

ユーザーがパスワードをリセットできるようにサポートを適切に実装するには、いくつかのルートを定義する必要があります。まず、ユーザーがメールアドレスを使用してパスワードリセットリンクをリクエストできるようにするための一対のルートが必要です。次に、ユーザーがメールで送信されたパスワードリセットリンクをクリックしてパスワードリセットフォームを完了するときに、実際にパスワードをリセットするための一対のルートが必要です。

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

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

まず、パスワードリセットリンクのリクエストが必要なルートを定義します。始めに、パスワードリセットリンクのリクエストフォームを含むビューを返すルートを定義します:

    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 言語ファイル内にあります。

注記

デフォルトでは、Laravelアプリケーションのスケルトンには lang ディレクトリが含まれていません。Laravelの言語ファイルをカスタマイズしたい場合は、lang:publish Artisanコマンドを使用して公開することができます。

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

注記

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

パスワードのリセット

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

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

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

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

フォームの送信を処理する

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

    use App\Models\User;
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 $user, string $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');

次に進む前に、このルートを詳しく調べてみましょう。まず、リクエストの tokenemailpassword 属性が検証されます。次に、Laravel の組込みの "password broker"(Password ファサードを介して)を使用して、パスワードリセットリクエストの資格情報を検証します。

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

reset メソッドは "status" スラッグを返します。このステータスは、ユーザーのリクエストのステータスに関するユーザーフレンドリーなメッセージを表示するために、Laravel の ローカライゼーション ヘルパーを使用して翻訳できます。パスワードリセットのステータスの翻訳は、アプリケーションの lang/{lang}/passwords.php 言語ファイルによって決定されます。ステータススラッグの各可能な値のエントリは、passwords 言語ファイル内にあります。アプリケーションに lang ディレクトリが含まれていない場合は、lang:publish Artisan コマンドを使用して作成できます。

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


## 期限切れトークンの削除

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

```shell
php artisan auth:clear-resets

このプロセスを自動化したい場合は、アプリケーションの スケジューラ にコマンドを追加することを検討してください:

    use Illuminate\Support\Facades\Schedule;

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

カスタマイズ

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

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

    use App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;

/**
* Bootstrap any application services.
*/
public function boot(): void
{
ResetPassword::createUrlUsing(function (User $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
*/
public function sendPasswordResetNotification($token): void
{
$url = 'https://example.com/reset-password?token='.$token;

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