Init
This commit is contained in:
534
output/12.x/passwords.md
Normal file
534
output/12.x/passwords.md
Normal file
@@ -0,0 +1,534 @@
|
||||
# Resetting Passwords
|
||||
|
||||
* Introduction
|
||||
* Configuration
|
||||
* Driver Prerequisites
|
||||
* Model Preparation
|
||||
* Configuring Trusted Hosts
|
||||
* Routing
|
||||
* Requesting the Password Reset Link
|
||||
* Resetting the Password
|
||||
* Deleting Expired Tokens
|
||||
* Customization
|
||||
|
||||
## Introduction
|
||||
|
||||
Most web applications provide a way for users to reset their forgotten
|
||||
passwords. Rather than forcing you to re-implement this by hand for every
|
||||
application you create, Laravel provides convenient services for sending
|
||||
password reset links and secure resetting passwords.
|
||||
|
||||
Want to get started fast? Install a Laravel [application starter
|
||||
kit](/docs/12.x/starter-kits) in a fresh Laravel application. Laravel's
|
||||
starter kits will take care of scaffolding your entire authentication system,
|
||||
including resetting forgotten passwords.
|
||||
|
||||
### Configuration
|
||||
|
||||
Your application's password reset configuration file is stored at
|
||||
`config/auth.php`. Be sure to review the options available to you in this
|
||||
file. By default, Laravel is configured to use the `database` password reset
|
||||
driver.
|
||||
|
||||
The password reset `driver` configuration option defines where password reset
|
||||
data will be stored. Laravel includes two drivers:
|
||||
|
||||
* `database` \- password reset data is stored in a relational database.
|
||||
* `cache` \- password reset data is stored in one of your cache-based stores.
|
||||
|
||||
### Driver Prerequisites
|
||||
|
||||
#### Database
|
||||
|
||||
When using the default `database` driver, a table must be created to store
|
||||
your application's password reset tokens. Typically, this is included in
|
||||
Laravel's default `0001_01_01_000000_create_users_table.php` database
|
||||
migration.
|
||||
|
||||
#### Cache
|
||||
|
||||
There is also a cache driver available for handling password resets, which
|
||||
does not require a dedicated database table. Entries are keyed by the user's
|
||||
email address, so ensure you are not using email addresses as a cache key
|
||||
elsewhere in your application:
|
||||
|
||||
|
||||
|
||||
1'passwords' => [
|
||||
|
||||
2 'users' => [
|
||||
|
||||
3 'driver' => 'cache',
|
||||
|
||||
4 'provider' => 'users',
|
||||
|
||||
5 'store' => 'passwords', // Optional...
|
||||
|
||||
6 'expire' => 60,
|
||||
|
||||
7 'throttle' => 60,
|
||||
|
||||
8 ],
|
||||
|
||||
9],
|
||||
|
||||
|
||||
'passwords' => [
|
||||
'users' => [
|
||||
'driver' => 'cache',
|
||||
'provider' => 'users',
|
||||
'store' => 'passwords', // Optional...
|
||||
'expire' => 60,
|
||||
'throttle' => 60,
|
||||
],
|
||||
],
|
||||
|
||||
To prevent a call to `artisan cache:clear` from flushing your password reset
|
||||
data, you can optionally specify a separate cache store with the `store`
|
||||
configuration key. The value should correspond to a store configured in your
|
||||
`config/cache.php` configuration value.
|
||||
|
||||
### Model Preparation
|
||||
|
||||
Before using the password reset features of Laravel, your application's
|
||||
`App\Models\User` model must use the `Illuminate\Notifications\Notifiable`
|
||||
trait. Typically, this trait is already included on the default
|
||||
`App\Models\User` model that is created with new Laravel applications.
|
||||
|
||||
Next, verify that your `App\Models\User` model implements the
|
||||
`Illuminate\Contracts\Auth\CanResetPassword` contract. The `App\Models\User`
|
||||
model included with the framework already implements this interface, and uses
|
||||
the `Illuminate\Auth\Passwords\CanResetPassword` trait to include the methods
|
||||
needed to implement the interface.
|
||||
|
||||
### Configuring Trusted Hosts
|
||||
|
||||
By default, Laravel will respond to all requests it receives regardless of the
|
||||
content of the HTTP request's `Host` header. In addition, the `Host` header's
|
||||
value will be used when generating absolute URLs to your application during a
|
||||
web request.
|
||||
|
||||
Typically, you should configure your web server, such as Nginx or Apache, to
|
||||
only send requests to your application that match a given hostname. However,
|
||||
if you do not have the ability to customize your web server directly and need
|
||||
to instruct Laravel to only respond to certain hostnames, you may do so by
|
||||
using the `trustHosts` middleware method in your application's
|
||||
`bootstrap/app.php` file. This is particularly important when your application
|
||||
offers password reset functionality.
|
||||
|
||||
To learn more about this middleware method, please consult the [TrustHosts
|
||||
middleware documentation](/docs/12.x/requests#configuring-trusted-hosts).
|
||||
|
||||
## Routing
|
||||
|
||||
To properly implement support for allowing users to reset their passwords, we
|
||||
will need to define several routes. First, we will need a pair of routes to
|
||||
handle allowing the user to request a password reset link via their email
|
||||
address. Second, we will need a pair of routes to handle actually resetting
|
||||
the password once the user visits the password reset link that is emailed to
|
||||
them and completes the password reset form.
|
||||
|
||||
### Requesting the Password Reset Link
|
||||
|
||||
#### The Password Reset Link Request Form
|
||||
|
||||
First, we will define the routes that are needed to request password reset
|
||||
links. To get started, we will define a route that returns a view with the
|
||||
password reset link request form:
|
||||
|
||||
|
||||
|
||||
1Route::get('/forgot-password', function () {
|
||||
|
||||
2 return view('auth.forgot-password');
|
||||
|
||||
3})->middleware('guest')->name('password.request');
|
||||
|
||||
|
||||
Route::get('/forgot-password', function () {
|
||||
return view('auth.forgot-password');
|
||||
})->middleware('guest')->name('password.request');
|
||||
|
||||
The view that is returned by this route should have a form containing an
|
||||
`email` field, which will allow the user to request a password reset link for
|
||||
a given email address.
|
||||
|
||||
#### Handling the Form Submission
|
||||
|
||||
Next, we will define a route that handles the form submission request from the
|
||||
"forgot password" view. This route will be responsible for validating the
|
||||
email address and sending the password reset request to the corresponding
|
||||
user:
|
||||
|
||||
|
||||
|
||||
1use Illuminate\Http\Request;
|
||||
|
||||
2use Illuminate\Support\Facades\Password;
|
||||
|
||||
3
|
||||
|
||||
4Route::post('/forgot-password', function (Request $request) {
|
||||
|
||||
5 $request->validate(['email' => 'required|email']);
|
||||
|
||||
6
|
||||
|
||||
7 $status = Password::sendResetLink(
|
||||
|
||||
8 $request->only('email')
|
||||
|
||||
9 );
|
||||
|
||||
10
|
||||
|
||||
11 return $status === Password::ResetLinkSent
|
||||
|
||||
12 ? back()->with(['status' => __($status)])
|
||||
|
||||
13 : back()->withErrors(['email' => __($status)]);
|
||||
|
||||
14})->middleware('guest')->name('password.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::ResetLinkSent
|
||||
? back()->with(['status' => __($status)])
|
||||
: back()->withErrors(['email' => __($status)]);
|
||||
})->middleware('guest')->name('password.email');
|
||||
|
||||
Before moving on, let's examine this route in more detail. First, the
|
||||
request's `email` attribute is validated. Next, we will use Laravel's built-in
|
||||
"password broker" (via the `Password` facade) to send a password reset link to
|
||||
the user. The password broker will take care of retrieving the user by the
|
||||
given field (in this case, the email address) and sending the user a password
|
||||
reset link via Laravel's built-in [notification
|
||||
system](/docs/12.x/notifications).
|
||||
|
||||
The `sendResetLink` method returns a "status" slug. This status may be
|
||||
translated using Laravel's [localization](/docs/12.x/localization) helpers in
|
||||
order to display a user-friendly message to the user regarding the status of
|
||||
their request. The translation of the password reset status is determined by
|
||||
your application's `lang/{lang}/passwords.php` language file. An entry for
|
||||
each possible value of the status slug is located within the `passwords`
|
||||
language file.
|
||||
|
||||
By default, the Laravel application skeleton does not include the `lang`
|
||||
directory. If you would like to customize Laravel's language files, you may
|
||||
publish them via the `lang:publish` Artisan command.
|
||||
|
||||
You may be wondering how Laravel knows how to retrieve the user record from
|
||||
your application's database when calling the `Password` facade's
|
||||
`sendResetLink` method. The Laravel password broker utilizes your
|
||||
authentication system's "user providers" to retrieve database records. The
|
||||
user provider used by the password broker is configured within the `passwords`
|
||||
configuration array of your `config/auth.php` configuration file. To learn
|
||||
more about writing custom user providers, consult the [authentication
|
||||
documentation](/docs/12.x/authentication#adding-custom-user-providers).
|
||||
|
||||
When manually implementing password resets, you are required to define the
|
||||
contents of the views and routes yourself. If you would like scaffolding that
|
||||
includes all necessary authentication and verification logic, check out the
|
||||
[Laravel application starter kits](/docs/12.x/starter-kits).
|
||||
|
||||
### Resetting the Password
|
||||
|
||||
#### The Password Reset Form
|
||||
|
||||
Next, we will define the routes necessary to actually reset the password once
|
||||
the user clicks on the password reset link that has been emailed to them and
|
||||
provides a new password. First, let's define the route that will display the
|
||||
reset password form that is displayed when the user clicks the reset password
|
||||
link. This route will receive a `token` parameter that we will use later to
|
||||
verify the password reset request:
|
||||
|
||||
|
||||
|
||||
1Route::get('/reset-password/{token}', function (string $token) {
|
||||
|
||||
2 return view('auth.reset-password', ['token' => $token]);
|
||||
|
||||
3})->middleware('guest')->name('password.reset');
|
||||
|
||||
|
||||
Route::get('/reset-password/{token}', function (string $token) {
|
||||
return view('auth.reset-password', ['token' => $token]);
|
||||
})->middleware('guest')->name('password.reset');
|
||||
|
||||
The view that is returned by this route should display a form containing an
|
||||
`email` field, a `password` field, a `password_confirmation` field, and a
|
||||
hidden `token` field, which should contain the value of the secret `$token`
|
||||
received by our route.
|
||||
|
||||
#### Handling the Form Submission
|
||||
|
||||
Of course, we need to define a route to actually handle the password reset
|
||||
form submission. This route will be responsible for validating the incoming
|
||||
request and updating the user's password in the database:
|
||||
|
||||
|
||||
|
||||
1use App\Models\User;
|
||||
|
||||
2use Illuminate\Auth\Events\PasswordReset;
|
||||
|
||||
3use Illuminate\Http\Request;
|
||||
|
||||
4use Illuminate\Support\Facades\Hash;
|
||||
|
||||
5use Illuminate\Support\Facades\Password;
|
||||
|
||||
6use Illuminate\Support\Str;
|
||||
|
||||
7
|
||||
|
||||
8Route::post('/reset-password', function (Request $request) {
|
||||
|
||||
9 $request->validate([
|
||||
|
||||
10 'token' => 'required',
|
||||
|
||||
11 'email' => 'required|email',
|
||||
|
||||
12 'password' => 'required|min:8|confirmed',
|
||||
|
||||
13 ]);
|
||||
|
||||
14
|
||||
|
||||
15 $status = Password::reset(
|
||||
|
||||
16 $request->only('email', 'password', 'password_confirmation', 'token'),
|
||||
|
||||
17 function (User $user, string $password) {
|
||||
|
||||
18 $user->forceFill([
|
||||
|
||||
19 'password' => Hash::make($password)
|
||||
|
||||
20 ])->setRememberToken(Str::random(60));
|
||||
|
||||
21
|
||||
|
||||
22 $user->save();
|
||||
|
||||
23
|
||||
|
||||
24 event(new PasswordReset($user));
|
||||
|
||||
25 }
|
||||
|
||||
26 );
|
||||
|
||||
27
|
||||
|
||||
28 return $status === Password::PasswordReset
|
||||
|
||||
29 ? redirect()->route('login')->with('status', __($status))
|
||||
|
||||
30 : back()->withErrors(['email' => [__($status)]]);
|
||||
|
||||
31})->middleware('guest')->name('password.update');
|
||||
|
||||
|
||||
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::PasswordReset
|
||||
? redirect()->route('login')->with('status', __($status))
|
||||
: back()->withErrors(['email' => [__($status)]]);
|
||||
})->middleware('guest')->name('password.update');
|
||||
|
||||
Before moving on, let's examine this route in more detail. First, the
|
||||
request's `token`, `email`, and `password` attributes are validated. Next, we
|
||||
will use Laravel's built-in "password broker" (via the `Password` facade) to
|
||||
validate the password reset request credentials.
|
||||
|
||||
If the token, email address, and password given to the password broker are
|
||||
valid, the closure passed to the `reset` method will be invoked. Within this
|
||||
closure, which receives the user instance and the plain-text password provided
|
||||
to the password reset form, we may update the user's password in the database.
|
||||
|
||||
The `reset` method returns a "status" slug. This status may be translated
|
||||
using Laravel's [localization](/docs/12.x/localization) helpers in order to
|
||||
display a user-friendly message to the user regarding the status of their
|
||||
request. The translation of the password reset status is determined by your
|
||||
application's `lang/{lang}/passwords.php` language file. An entry for each
|
||||
possible value of the status slug is located within the `passwords` language
|
||||
file. If your application does not contain a `lang` directory, you may create
|
||||
it using the `lang:publish` Artisan command.
|
||||
|
||||
Before moving on, you may be wondering how Laravel knows how to retrieve the
|
||||
user record from your application's database when calling the `Password`
|
||||
facade's `reset` method. The Laravel password broker utilizes your
|
||||
authentication system's "user providers" to retrieve database records. The
|
||||
user provider used by the password broker is configured within the `passwords`
|
||||
configuration array of your `config/auth.php` configuration file. To learn
|
||||
more about writing custom user providers, consult the [authentication
|
||||
documentation](/docs/12.x/authentication#adding-custom-user-providers).
|
||||
|
||||
## Deleting Expired Tokens
|
||||
|
||||
If you are using the `database` driver, password reset tokens that have
|
||||
expired will still be present within your database. However, you may easily
|
||||
delete these records using the `auth:clear-resets` Artisan command:
|
||||
|
||||
|
||||
|
||||
1php artisan auth:clear-resets
|
||||
|
||||
|
||||
php artisan auth:clear-resets
|
||||
|
||||
If you would like to automate this process, consider adding the command to
|
||||
your application's [scheduler](/docs/12.x/scheduling):
|
||||
|
||||
|
||||
|
||||
1use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
2
|
||||
|
||||
3Schedule::command('auth:clear-resets')->everyFifteenMinutes();
|
||||
|
||||
|
||||
use Illuminate\Support\Facades\Schedule;
|
||||
|
||||
Schedule::command('auth:clear-resets')->everyFifteenMinutes();
|
||||
|
||||
## Customization
|
||||
|
||||
#### Reset Link Customization
|
||||
|
||||
You may customize the password reset link URL using the `createUrlUsing`
|
||||
method provided by the `ResetPassword` notification class. This method accepts
|
||||
a closure which receives the user instance that is receiving the notification
|
||||
as well as the password reset link token. Typically, you should call this
|
||||
method from the `boot` method of your application's `AppServiceProvider`:
|
||||
|
||||
|
||||
|
||||
1use App\Models\User;
|
||||
|
||||
2use Illuminate\Auth\Notifications\ResetPassword;
|
||||
|
||||
3
|
||||
|
||||
4/**
|
||||
|
||||
5 * Bootstrap any application services.
|
||||
|
||||
6 */
|
||||
|
||||
7public function boot(): void
|
||||
|
||||
8{
|
||||
|
||||
9 ResetPassword::createUrlUsing(function (User $user, string $token) {
|
||||
|
||||
10 return 'https://example.com/reset-password?token='.$token;
|
||||
|
||||
11 });
|
||||
|
||||
12}
|
||||
|
||||
|
||||
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;
|
||||
});
|
||||
}
|
||||
|
||||
#### Reset Email Customization
|
||||
|
||||
You may easily modify the notification class used to send the password reset
|
||||
link to the user. To get started, override the `sendPasswordResetNotification`
|
||||
method on your `App\Models\User` model. Within this method, you may send the
|
||||
notification using any [notification class](/docs/12.x/notifications) of your
|
||||
own creation. The password reset `$token` is the first argument received by
|
||||
the method. You may use this `$token` to build the password reset URL of your
|
||||
choice and send your notification to the user:
|
||||
|
||||
|
||||
|
||||
1use App\Notifications\ResetPasswordNotification;
|
||||
|
||||
2
|
||||
|
||||
3/**
|
||||
|
||||
4 * Send a password reset notification to the user.
|
||||
|
||||
5 *
|
||||
|
||||
6 * @param string $token
|
||||
|
||||
7 */
|
||||
|
||||
8public function sendPasswordResetNotification($token): void
|
||||
|
||||
9{
|
||||
|
||||
10 $url = 'https://example.com/reset-password?token='.$token;
|
||||
|
||||
11
|
||||
|
||||
12 $this->notify(new ResetPasswordNotification($url));
|
||||
|
||||
13}
|
||||
|
||||
|
||||
use App\Notifications\ResetPasswordNotification;
|
||||
|
||||
/**
|
||||
* Send a password reset notification to the user.
|
||||
*
|
||||
* @param string $token
|
||||
*/
|
||||
public function sendPasswordResetNotification($token): void
|
||||
{
|
||||
$url = 'https://example.com/reset-password?token='.$token;
|
||||
|
||||
$this->notify(new ResetPasswordNotification($url));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user