Сброс пароля
Введение
Большинство веб-приложений предоставляют пользователям возможность сбросить забытые пароли. Вместо того, чтобы заставлять вас заново реализовывать это вручную для каждого создаваемого вами приложения, Laravel предоставляет удобные сервисы для отправки ссылок для сброса пароля и безопасного сброса паролей.
{tip} Хотите начать быстро? Установите Laravel стартовый набор приложений в новое приложение Laravel. Стартовые наборы Laravel позаботятся о создании всей вашей системы аутентификации, включая сброс забытых паролей.
Подготовка модели
Прежде чем использовать функции сброса пароля Laravel, модель App\Models\User
вашего приложения должна использовать трейт Illuminate\Notifications\Notifiable
. Как правило, этот трейт уже включен в модель App\Models\User
по умолчанию, которая создается с новыми приложениями Laravel.
Затем убедитесь, что ваша модель App\Models\User
реализует контракт Illuminate\Contracts\Auth\CanResetPassword
. Модель App\Models\User
, входящая в состав фреймворка, уже реализует этот интерфейс и использует трейт Illuminate\Auth\Passwords\CanResetPassword
для включения методов, необходимых для реализации интерфейса.
Подготовка базы данных
Необходимо создать таблицу для хранения токенов сброса пароля вашего приложения. Миграция для этой таблицы включена в приложение Laravel по умолчанию, поэтому вам нужно только перенести базу данных, чтобы создать эту таблицу:
php artisan migrate
Настройка доверенных хостов
По умолчанию Laravel будет отвечать на все запросы, которые он получает, независимо от содержимого заголовка Host
HTTP-запроса. Кроме того, значение заголовка Host
будет использоваться при создании абсолютных URL-адресов для вашего приложения во время веб-запроса.
Как правило, вы должны настроить свой веб-сервер, такой как Nginx или Apache, так, чтобы он отправлял вашему приложению только те запросы, которые соответствуют заданному имени хоста. Однако, если у вас нет возможности настраивать свой веб-сервер напрямую и вам нужно указать Laravel отвечать только на определенные имена хостов, вы можете сделать это, включив мидлвар App\Http\Middleware\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
возвращает слаг «статуса». Этот статус можно перевести с помощью помощников Laravel локализации, чтобы отобразить пользователю удобное сообщение о статусе его запроса. Перевод состояния сброса пароля определяется языковым файлом resources/lang/{lang}/passwords.php
вашего приложения. Запись для каждого возможного значения слага состояния находится в языковом файле passwords
.
Вам может быть интересно, как Laravel знает, как получить запись пользователя из базы данных вашего приложения при вызове метода sendResetLink
фасада Password
. Брокер паролей Laravel использует «поставщиков пользователей» вашей системы аутентификации для извлечения записей из базы данных. Пользовательский провайдер, используемый брокером паролей, настраивается в массиве конфигурации passwords
вашего конфигурационного файла config/auth.php
. Чтобы узнать больше о написании пользовательских провайдеров пользователей, обратитесь к документации по аутентификации.
{tip} При ручной реализации сброса пароля вам необходимо самостоятельно определить содержимое представлений и маршрутов. Если вам нужен каркас, включающий всю необходимую логику аутентификации и проверки, ознакомьтесь со стартовыми наборами приложений 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');
Прежде чем двигаться дальше, давайте рассмотрим этот маршрут более подробно. Сначала проверяются атрибуты token
, email
и password
. Далее мы будем использовать встроенный в Laravel «брокер паролей» (через фасад Password
) для проверки учетных данных запроса на сброс пароля.
Если токен, адрес электронной почты и пароль, предоставленные брокеру паролей, действительны, замыкание, переданное методу reset
, будет вызвано. В рамках этого замыкания, которое получает экземпляр пользователя и текстовый пароль, предоставленный форме сброса пароля, мы можем обновить пароль пользователя в базе данных.
Метод reset
возвращает слаг «статуса». Этот статус можно перевести с помощью помощников Laravel localization, чтобы отобразить пользователю удобное сообщение о статусе его запроса. Перевод состояния сброса пароля определяется языковым файлом resources/lang/{lang}/passwords.php
вашего приложения. Запись для каждого возможного значения слага состояния находится в языковом файле passwords
.
Прежде чем двигаться дальше, вам может быть интересно, как Laravel знает, как получить запись пользователя из базы данных вашего приложения при вызове метода reset
фасада Password
. Брокер паролей Laravel использует «поставщиков пользователей» вашей системы аутентификации для извлечения записей из базы данных. Пользовательский провайдер, используемый брокером паролей, настраивается в массиве конфигурации passwords
вашего конфигурационного файла config/auth.php
. Чтобы узнать больше о написании пользовательских провайдеров пользователей, обратитесь к документации по аутентификации.
Удаление токенов с истекшим сроком действия
Жетоны сброса пароля, срок действия которых истек, все еще будут присутствовать в вашей базе данных. Однако вы можете легко удалить эти записи с помощью Artisan-команды auth:clear-resets
:
php artisan auth:clear-resets
Если вы хотите автоматизировать этот процесс, рассмотрите возможность добавления команды в планировщике вашего приложения:
$schedule->command('auth:clear-resets')->everyFifteenMinutes();
Настройка
Сбросить настройку ссылки
Вы можете настроить URL-адрес ссылки для сброса пароля, используя метод createUrlUsing
, предоставляемый классом уведомлений ResetPassword
. Этот метод принимает замыкание, которое получает экземпляр пользователя, получающего уведомление, а также токен ссылки для сброса пароля. Как правило, этот метод следует вызывать из метода boot
поставщика услуг App\Providers\AuthServiceProvider
:
use Illuminate\Auth\Notifications\ResetPassword; /** * Register any authentication / authorization services. * * @return void */public function boot(){ $this->registerPolicies(); ResetPassword::createUrlUsing(function ($user, string $token) { return 'https://example.com/reset-password?token='.$token; });}
Сбросить настройку электронной почты
Вы можете легко изменить класс уведомления, используемый для отправки пользователю ссылки для сброса пароля. Для начала переопределите метод sendPasswordResetNotification
в вашей модели App\Models\User
. В рамках этого метода вы можете отправить уведомление, используя любой класс уведомлений, созданный вами. Сброс пароля $token
является первым аргументом, полученным методом. Вы можете использовать этот $token
для создания URL-адреса для сброса пароля по вашему выбору и отправки уведомления пользователю:
use App\Notifications\ResetPasswordNotification; /** * Send a password reset notification to the user. * * @param string $token * @return void */public function sendPasswordResetNotification($token){ $url = 'https://example.com/reset-password?token='.$token; $this->notify(new ResetPasswordNotification($url));}