#Введение
Большинство веб-приложений предоставляют пользователям возможность сбросить забытый пароль. Вместо того чтобы реализовывать это вручную для каждого приложения, 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 отвечает на все запросы, независимо от содержимого заголовка HTTP Host. Кроме того, значение заголовка Host используется при генерации абсолютных URL вашего приложения во время веб-запроса.
Обычно следует настроить веб-сервер, например Nginx или Apache, так, чтобы он отправлял запросы вашему приложению только с определённого имени хоста. Однако если у вас нет возможности напрямую настраивать веб-сервер и нужно ограничить Laravel для ответа только на определённые имена хостов, вы можете включить промежуточное ПО App\Http\Middleware\TrustHosts в вашем приложении. Это особенно важно, если ваше приложение предоставляет функциональность сброса пароля.
Чтобы узнать больше об этом промежуточном ПО, обратитесь к документации по TrustHosts middleware.
#Маршрутизация
Для корректной реализации поддержки сброса пароля пользователями необходимо определить несколько маршрутов. Во-первых, нужны маршруты для запроса ссылки на сброс пароля по электронной почте. Во-вторых, маршруты для самого сброса пароля после перехода пользователя по ссылке и заполнения формы сброса.
#Запрос ссылки для сброса пароля
#Форма запроса ссылки для сброса пароля
Сначала определим маршруты для запроса ссылок на сброс пароля. Для начала создадим маршрут, который возвращает представление с формой запроса ссылки для сброса пароля:
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 из запроса. Затем используется встроенный "password broker" Laravel (через фасад Password) для отправки ссылки на сброс пароля пользователю. Password broker автоматически находит пользователя по указанному полю (в данном случае по email) и отправляет ему ссылку через встроенную систему уведомлений.
Метод sendResetLink возвращает slug "status". Этот статус можно перевести с помощью хелперов Laravel для локализации, чтобы показать пользователю понятное сообщение о результате его запроса. Перевод статуса сброса пароля определяется языковым файлом вашего приложения lang/{lang}/passwords.php. Запись для каждого возможного значения этого slug находится в языковом файле passwords.
По умолчанию в скелете приложения Laravel отсутствует директория lang. Если вы хотите изменить языковые файлы Laravel, вы можете опубликовать их с помощью Artisan-команды lang:publish.
Возможно, вы задаётесь вопросом, как Laravel узнаёт, как получить запись пользователя из базы данных при вызове метода sendResetLink фасада Password. Password broker использует "user providers" вашей системы аутентификации для получения записей из базы. Провайдер пользователя, используемый password broker, настраивается в массиве passwords в конфигурационном файле config/auth.php. Подробнее о создании кастомных провайдеров пользователей читайте в документации по аутентификации.
При ручной реализации сброса пароля вам нужно самостоятельно определить содержимое представлений и маршрутов. Если вы хотите получить готовое решение с полной логикой аутентификации и верификации, ознакомьтесь с стартовыми наборами 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');
Прежде чем продолжить, рассмотрим этот маршрут подробнее. Сначала происходит валидация атрибутов token, email и password из запроса. Затем используется встроенный "password broker" Laravel (через фасад Password) для проверки данных запроса на сброс пароля.
Если токен, адрес электронной почты и пароль, переданные password broker, валидны, будет вызвана переданная в метод reset замыкание. В этом замыкании, которое получает экземпляр пользователя и переданный в форму сброса пароль в открытом виде, мы можем обновить пароль пользователя в базе данных.
Метод reset возвращает slug статуса. Этот статус можно перевести с помощью хелперов Laravel для локализации, чтобы показать пользователю понятное сообщение о статусе его запроса. Перевод статуса сброса пароля определяется файлом локализации вашего приложения lang/{lang}/passwords.php. Запись для каждого возможного значения slug статуса находится в файле локализации passwords. Если в вашем приложении отсутствует каталог lang, вы можете создать его с помощью команды Artisan lang:publish.
Возможно, вы задаётесь вопросом, как Laravel узнаёт, как получить запись пользователя из базы данных при вызове метода reset фасада Password. Password broker использует "user providers" вашей системы аутентификации для получения записей из базы. Провайдер пользователя, используемый password broker, настраивается в массиве 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 App\Models\User;
use Illuminate\Auth\Notifications\ResetPassword;
/**
* Регистрация сервисов аутентификации и авторизации.
*/
public function boot(): void
{
ResetPassword::createUrlUsing(function (User $user, string $token) {
return 'https://example.com/reset-password?token='.$token;
});
}
#Настройка письма для сброса пароля
Вы можете легко изменить класс уведомления, который отправляет ссылку для сброса пароля пользователю. Для начала переопределите метод sendPasswordResetNotification в вашей модели App\Models\User. В этом методе вы можете отправить уведомление, используя любой класс уведомления, созданный вами. Токен сброса пароля $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));
}