1. Безопасность
  2. Сброс пароля

Введение

Большинство веб-приложений предоставляют пользователям способ сбросить забытые пароли. Вместо того чтобы заставлять вас реализовывать это вручную для каждого приложения, которое вы создаете, Laravel предоставляет удобные сервисы для отправки ссылок для сброса пароля и безопасного сброса паролей.

Примечание Хотите начать быстро? Установите набор стартового кода приложения 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.

Маршрутизация

Для правильной поддержки возможности сброса пароля пользователям необходимо определить несколько маршрутов. Во-первых, нам понадобится пара маршрутов для обработки запроса пользователя на получение ссылки для сброса пароля по электронной почте. Во-вторых, нам понадобится пара маршрутов для обработки самого сброса пароля, когда пользователь посещает отправленную ему по электронной почте ссылку и завершает форму сброса пароля.

Запрос ссылки сброса пароля

Форма запроса сброса пароля

Сначала мы определим маршруты, необходимые для запроса ссылок для сброса пароля. Для начала определим маршрут, который возвращает представление с формой запроса ссылки для сброса пароля:

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, чтобы отобразить дружественное сообщение пользователю относительно статуса его запроса. Перевод статуса сброса пароля определяется языковым файлом вашего приложения lang/{lang}/passwords.php. Запись для каждого возможного значения метки статуса находится в файле языка passwords.

Примечание По умолчанию образец приложения Laravel не включает в себя каталог lang. Если вы хотите настроить языковые файлы Laravel, вы можете опубликовать их с помощью команды lang:publish Artisan.

Возможно, вы задаетесь вопросом, как Laravel узнает, как извлечь запись пользователя из базы данных вашего приложения при вызове метода sendResetLink фасада Password. Брокер паролей Laravel использует "поставщики пользователей" вашей системы аутентификации для извлечения записей из базы данных. Поставщик пользователей, используемый брокером паролей, настраивается в массиве конфигурации 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 запроса. Затем мы будем использовать встроенный в Laravel "парольный брокер" (через фасад Password), чтобы проверить учетные данные запроса на сброс пароля.

Если токен, адрес электронной почты и пароль, переданные парольному брокеру, являются допустимыми, будет вызван замыкание, переданное методу reset. Внутри этого замыкания, которое получает экземпляр пользователя и обычный текстовый пароль, предоставленный форме сброса пароля, мы можем обновить пароль пользователя в базе данных.

Метод reset возвращает «статус». Этот статус можно перевести с использованием средств локализации Laravel, чтобы отобразить пользователю дружелюбное сообщение о состоянии его запроса. Перевод статуса сброса пароля определяется языковым файлом lang/{lang}/passwords.php вашего приложения. Запись для каждого возможного значения статуса находится в файле языка passwords. Если ваше приложение не содержит каталога lang, вы можете создать его с помощью команды lang:publish Artisan.

Прежде чем двигаться дальше, вам может быть интересно, как Laravel узнает, как извлекать запись пользователя из базы данных вашего приложения при вызове метода reset фасада Password. Брокер паролей Laravel использует поставщиков пользователей вашей системы аутентификации для извлечения записей из базы данных. Поставщик пользователей, используемый брокером паролей, настроен в массиве конфигурации passwords файла конфигурации config/auth.php вашего приложения. Чтобы узнать больше о написании пользовательских поставщиков, ознакомьтесь с документацией по аутентификации.

Удаление устаревших токенов

Токены сброса пароля, которые устарели, все равно остаются в вашей базе данных. Однако вы можете легко удалить эти записи с помощью команды auth:clear-resets Artisan:

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));
}