Аутентификация
Содержание:
Введение
Хотите быстрый старт? Просто выполните команду php artisan make:auth
и
php artisan migrate
для нового приложения Ларавел. После чего откройте
адрес http://your-app.test/register
в браузере или другой маршрут вашего
приложения. Эти две команды позаботятся о реализации системы аутентификации для вашего
приложения.
Ларавел делает реализацию аутентификации очень простой. По факту, все уже настроено
для вас из коробки. Файл конфигурации для аутентификации располагается в
config/auth.php
, который содержит несколько хорошо документированных пунктов
для точной настройки поведения сервисов аутентификации.
Возможности аутентификации Ларавел делятся на "защитников" и "провайдеров". Защитники
определяют то, как пользователи были аутентифицированы для каждого запроса. Например,
Laravel защитник session
, который поддерживает состояние используя
хранилище сессий и cookies.
Провайдеры определяют каким образом пользователи извлекаются из вашего постоянного хранилища.
Ларавел предусмотрена поддержка и извлечении пользователей с использованием Eloquent и
конструктор запросов к базе данных. Однако, вы можете легко определить
дополнительных провайдеров, которые необходимы для вашего приожения.
Не стоит беспокоится, если это воспринимается слишком сложно сейчас. Со временим, появятся знания,
и вы сможете детально разобраться во всех нюансах. К слову, для большинства приложений вам
никогда не придется менять базовую конфигурацию системы.
Решения по базе данных
По умолчанию, Ларавел включает App\User
модель
Eloquent в вашей папке app
.
Эту модель можно использовать для базоваго драйвера аутентификации Eloquent. Если ваше приложение
не использует Eloquent, вы можете использовать драйвер аутентификации database
,
который использует конструктор запросов Ларавел.
При построении базы данных для модели App\User
, убедитесь в том, что колонка
пароля длиной в 60 символов как минимум. Хорошим выбором будет указать значение длины колонки
в 255 символов.
Также вы должны провести верификацию того, что ваша таблица users
(или эквивалент)
содержит nullable строку remember_token
из 100 символов. Эта колонка будет использоваться
для хранения токена для пользователей, которые выбрали пункт "запомнить меня" при входе
в приложение.
Быстрый старт
Laravel поставляется с несколькими встроенными контроллерами аутентификации, которые расположены
в App\Http\Controllers\Auth
. RegisterController
обрабатывает регистрацию
новых пользователей, LoginController
работает с аутентификацией,
ForgotPasswordController
высылает ссылки электронной почты для того, чтобы задать
новый пароль, и ResetPasswordController
содержит логику присвоения новых паролей.
Каждый из этих контроллеров используют трейты для включения необходимых методов. Для большгого
количества приложений вам не потребуется модифицировать эти контроллеры вовсе.
Маршрутизация
Ларавел предоставляет быстрый способ настроить маршруты, файлы и всё что нужно для аутентификации
используя одну простую команду:
php artisan make:auth
Эту команду нужно использовать для новых установок Ларавел. После её выполнения, вы получите
представления регистрации и для логина, а также маршруты для всех конечных точен аутентификации.
Будет также сгенерирван HomeController
для обработки запросов логина в панель
управления вашего приложения.
Если ваше приложение не нуждается в регистрации, вы можете отключить путём удаления
только что созданного RegisterController
, а также изменить декларацию
маршрута: Auth::routes(['register' => false]);
.
Представления
Как и упоминалось в предыдущей секции, команда php artisan make:auth
создаст
все необходимы для аутентификации представления и разместит их в папке
resources/views/auth
.
Команда make:auth
также создаст папку resources/views/layouts
,
которая содержит базовый шаблон для вашего приложения. Все эти представления используют
CSS фреймворк Bootstrap, конечно вы можете легко заменить его на любой другой или собственный.
Аутентификация
Теперь после установки маршрутов и представлений для включённых контроллеров аутентификации,
вы готовы зарегистрировать и провести аутентификцию новых пользователей для вашего приложения.
В силу того, что вся логика взаимодействия с пользователями уже есть, вы можете войти в ваше
приложение в браузере.
Настройка путей
После успешной аутентификации пользователя, он может быть перенаправлен на страницу
/home
. Вы можете настроить перенаправление путём определения свойства
redirectTo
в контроллерах: LoginController
, RegisterController
,
ResetPasswordController
, и VerificationController
:
protected $redirectTo = '/';
После чего, вы должны модифицировать метод RedirectIfAuthenticated
для
посредника handle
, чтобы использовать новый URI при перенаправлении
пользователя.
Если вам необходимо внедрить некоторую логику для перенаправления,
тогда вы можете использовать метод redirectTo
вместо
свойства redirectTo
:
protected function redirectTo()
{
return '/path';
}
Метод redirectTo
имеет приоритет над атрибутом
redirectTo
.
Настройка имени пользователя
По умолчанию, Ларавел использует поле email
для аутентификации. Если вы хотите изменить
это, вы можете определить метод username
для вашего LoginController
:
public function username()
{
return 'username';
}
Настройка защитника
Вы также можете настроить защитника, который используется для аутентификации и регистрации
пользователей. Для начала, определите метод guard
для ваших LoginController
,
RegisterController
, и ResetPasswordController
. Этот метод должен вернуть
экземпляр стража:
use Illuminate\Support\Facades\Auth;
protected function guard()
{
return Auth::guard('guard-name');
}
Валидация / Настройка хранилища
Чтобы модифицировать поля формы, которые необходимы при регистрации нового пользователя или
настроить как новый пользователь попадает в вашу базу данных, нужно модифицировать класс
RegisterController
. Этот класс отвечает за валидаци и создание нового пользователя
для вашего приложения.
Метод validator
контроллера RegisterController
содержит правила
валидации для новых пользователей приложения. Вы можете модифицировать этот метод как захотите.
Метод create
для контроллера RegisterController
отвечает за создание
новой записи App\User
в вашей базе данных используя Eloquent. Вы можете изменить
этот метод как считаете необходимым.
Получение пользователей, которые прошли аутинтификацию
Вы можете получить доступ к аутентифицированному пользователю через фасад Auth
:
use Illuminate\Support\Facades\Auth;
// Get the currently authenticated user...
$user = Auth::user();
// Get the currently authenticated user's ID...
$id = Auth::id();
Как вариант, вы можете получить доступ к пользователю через экземпляр
Illuminate\Http\Request
. Как обычно. вписанные классы будут автоматически
внедрены в методы контроллера:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class ProfileController extends Controller
{
/**
* Update the user's profile.
*
* @param Request $request
* @return Response
*/
public function update(Request $request)
{
// $request->user() returns an instance of the authenticated user...
}
}
Определение того, что текущий пользователь аутентифицирован
Чтобы определить, что текущий пользователь уже вошел в ваше приложение, вы можете использовать
метод check
для фасада Auth
, который вернёт true
, если
пользователь аутентифицирован:
use Illuminate\Support\Facades\Auth;
if (Auth::check()) {
// The user is logged in...
}
Хоть есть такая возможность опрелить, что пользователь вошел через метод check
,
обычно вы будете использовать посредника для верификации аутентификации пользователя
до момента доступа к определённым маршрутам и контроллерам. Больше информации можете
узнать из следующего раздела.
Защита маршрутов
Можно использовать посредник для того, чтобы только аутентифицированным пользователям позволить
получить доступ к представленному маршруту. Ларавел поставляется с включённым посредником auth
,
который определён в Illuminate\Auth\Middleware\Authenticate
. В силу того, что данный
посредник уже зарегистрирован, всё что вам необходимо — это прикрепить посредника к
определению маршрута:
Route::get('profile', function () {
// Only authenticated users may enter...
})->middleware('auth');
Когда вы используете контроллер, вы можете вызвать метод middleware
из
конструктора контроллера, вместо прикрепления его к определению маршрута напрямую:
public function __construct()
{
$this->middleware('auth');
}
Перенаправление пользователей без аутентификации
Когда посредник auth
определил неавторизованного пользователя, он автоматически
перенаправит пользователя на странуцу логин
. Мы можете изменить такое поведение
путём обновления функции redirectTo
в вашем файле
app/Http/Middleware/Authenticate.php
:
/**
* Get the path the user should be redirected to.
*
* @param \Illuminate\Http\Request $request
* @return string
*/
protected function redirectTo($request)
{
return route('login');
}
Указание стража
При прикреплении посредника auth
к маршруты, вы можете также указать какой страж
должен быть использован для аутентификации пользователя. Страж должен соответствавать одному
из ключей в массиве guards
в вашем файле конфигурации auth.php
:
public function __construct()
{
$this->middleware('auth:api');
}
Регулириование входа
Если вы используете встроенный в Ларавел класс LoginController
,
трейт Illuminate\Foundation\Auth\ThrottlesLogins
будет уже включён в контроллер.
По умолчанию, пользователь не сможет залогиниться в течение минуты, если не предоставили
верных учётных данных после несокольких попыток. Блокировка привязана к имени пользователя,
e-mail адресу или IP адресу.
Проверка подлинности пользователй вручную
Вам не обязательно использовать контроллеры аутентификации включённые в Ларавел.
Если вы выберите убрать эти контроллеры, вам будет необходимо использовать
классы аутентификации напрямую.
Получить доступ к сервисам аутентификации Ларавел можно через фасад Auth
,
поэтому необходимо убедиться в том, что мы импортировали фасад Auth
вверху
нашего класса. Далее, давайте проверим метод attempt
:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
class LoginController extends Controller
{
/**
* Handle an authentication attempt.
*
* @param \Illuminate\Http\Request $request
*
* @return Response
*/
public function authenticate(Request $request)
{
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
// Authentication passed...
return redirect()->intended('dashboard');
}
}
}
Метод attempt
принимает массив пар ключ / значение в качестве первого аргумента.
Значения в массиве будут использоваться, чтобы найти пользователя в вашей таблице бд.
Поэтому, в верхнем примере, мы получим пользователя по значеню для колонки email
.
Если такой пользователь существует, захэшированный пароль сохранённый в базе данных будет
сравниваться со значением password
, которое передали в метод через массив.
Вам не нужно хэшировать значение password
, в силу того что фреймворк автоматически
хэширует значение до момента сравнения с захэшированным паролем в базе данных. Если два знечения
совпадают, тогда аутентентифицированная сессия будет начата для пользователя.
Метод attempt
вернёт true
если аутентификация успешна.
В противном случае вернётся значение false
.
Метод intended
для редиректора будет перенаправлять пользователя на URL, который
они пытаются посетить, до момента перехвата запроса посредником аутентификации.
Этот метод можно использовать как резервный URL, для случая когда желаемый адрес недоступен.
Указание дополнительных условий
Если вы хотите, вы можете добавить дополнительный условия для запроса аутентификации в дполнение к
email и паролю пользователя. Например, вы можете верефицировать, что пользоватлеь отмечен как
"активный":
if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
// The user is active, not suspended, and exists.
}
В этих примерах, email
это необязательная опция, использовалась просто как пример.
Вы должны использовать такое имя колонки, которое соответсвует "username" в базе данных.
Доступ к конкретным экземплярам стража
Вы можете указать какой экземпляр стража вы хотите применить используя метод guard
для фасада Auth
. Это позволит вам управлять проверкой подлинности для отдельных частей
вашего приложения, используя абсолютно разные модели аутентификации или таблицы пользователя.
Имя стража, передаваемого в метод guard
должно соответсвовать одному из значений,
настроенных в вашем файле конфигурации auth.php
:
if (Auth::guard('admin')->attempt($credentials)) {
//
}
Выход из приложения
Для того чтобы вывести пользователя из вашего приложения, вы можете использовать метод logout
для фасада Auth
. Это очистит информацию о пользовательской сессии:
Auth::logout();
Запоминание пользователя
Если вы хотите обеспечить функциональность ввиде отметки "запомнить меня" для вашего приложения,
вы можете передать логическое значение в качестве второго аргумента в метод attempt
,
который будет держать пользователя утентифицированным на неопределенный срок, либо до момента
выхода в ручном режиме. Ваша таблица users
должна включать строковую колонку
remember_token
, которая будет использоваться для хранения токена "запомнить меня".
if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) {
// The user is being remembered...
}
Если вы используете встроенный контроллер LoginController
, необходимая логика для
"запоминания" уже реализована путём использования трейтов контроллером.
Если вы запоминаете пользователей, вы можете использовать метод viaRemember
,
чтобы определить, что пользователь аутентифицирован используя "запомнить меня" cookie:
if (Auth::viaRemember()) {
//
}
Другие методы
Аутентификация экземпляра пользователя
Если необходимо залогинить экземпляр существующего пользователя в приложение, вы можете вызвать
метод login
с экземпляром пользователя. Данный объект должен быть реализацией
контракта Illuminate\Contracts\Auth\Authenticatable
. Включённая в Ларавел модель
уже расширяет этот интерфейс:
Auth::login($user);
// Login and "remember" the given user...
Auth::login($user, true);
Вы можете указать стража, которого хотите использовать:
Auth::guard('admin')->login($user);
Аутентификация пользователя по ID
Чтобы залогинить пользователя в приложении по ID, вы можете использовать метод
loginUsingId
. Этот метод принимает первичный ключ пользователя, которого
вы вы хотите аутентифицировать:
Auth::loginUsingId(1);
// Login and "remember" the given user...
Auth::loginUsingId(1, true);
Одноразовая аутентификация пользователя
Вы может использовать метод once
, чтобы залогинить пользователя в приложении
для одного запроса. В этом случае не используются сессии или cookies. Фактически, этот метод
может быть полезен для API:
if (Auth::once($credentials)) {
//
}
Базовая аутинтификация HTTP
Базовая HTTP аутентификация
предоставляет быстрый способ аутентификации пользователей вашего приложения без создания дополнительной
страницы "логин". Для начала, прикрепите посредника auth.basic
к вашему маршруту. Его не
нужно определять, из-за того, что он влючён в Ларавел:
Route::get('profile', function () {
// Only authenticated users may enter...
})->middleware('auth.basic');
После того, как посредник был прикреплён к маршруту, вы автоматически получите предложение
ввести учётные данные при обращении к маршруту в вашем браузере. По умолчанию, посредник
auth.basic
будет использовать колонку email
из записи пользователя
в качестве "username".
Заметка о FastCGI
Если вы используете PHP FastCGI, базовая аутентификация HTTP может не работать как нужно
из коробки. Следующие строки должны быть добавлены в файл .htaccess
:
RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
Базовая аутинтификация HTTP без прав
Вы также можете использовать базовую HTTP аутентификацию без установления идентификатора
cookie в сессии, что может быть полезна для API аутентификации. Чтобы это сделать, определите
посредника, который вызывает метод onceBasic
. Если метод onceBasic
не возвращает ответа, запрос можно пропустить дальше в приложение:
<?php
namespace App\Http\Middleware;
use Illuminate\Support\Facades\Auth;
class AuthenticateOnceWithBasicAuth
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, $next)
{
return Auth::onceBasic() ?: $next($request);
}
}
Следующим шагом зарегистрируйте
посредник
и прикрепите его к маршруту:
Route::get('api/user', function () {
// Only authenticated users may enter...
})->middleware('auth.basic.once');
Выход
Чтобы вручную вывести пользователия из приложения, вы можете использовато метод logout
для фасада Auth
. Такое действие удалит всю информацию о сессии пользователя:
use Illuminate\Support\Facades\Auth;
Auth::logout();
Аннулирование сейансов на других устройствах
Ларавел также обеспечивает механизм для анулирования пользовательских сессий,
которые активны на других устройствах, без анулирования сессии для текущего устройства.
Перед началом, необходимо убедиться в том, что посрденик
Illuminate\Session\Middleware\AuthenticateSession
присутствует и
не закоментирован в классе app/Http/Kernel.php
группе посредников
web
:
'web' => [
// ...
\Illuminate\Session\Middleware\AuthenticateSession::class,
// ...
],
После чего, вы можете использоват метод logoutOtherDevices
для
фасада Auth
. Этот метод требует от пользователя предоставить текущий пароль,
который ваше приложение должно принять через форму ввода:
use Illuminate\Support\Facades\Auth;
Auth::logoutOtherDevices($password);
При вызове метода logoutOtherDevices
все остальные сессии пользователя
будут анулированы, что означает, пользователь будет выведен из всех стражей,
в которых ранее он был аутентифицирован.
Добавление пользовательских защитников
Вы можете определить ваших собственных стражей аутентификации используя метод
extend
для фасада Auth
. Вы должны разместить этот вызов
в extend
внутри
сервис провайдера.
В силу того, что в Ларавел уже есть AuthServiceProvider
, мы можем
разместить код в этом провайдере:
<?php
namespace App\Providers;
use App\Services\Auth\JwtGuard;
use Illuminate\Support\Facades\Auth;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* Register any application authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Auth::extend('jwt', function ($app, $name, array $config) {
// Return an instance of Illuminate\Contracts\Auth\Guard...
return new JwtGuard(Auth::createUserProvider($config['provider']));
});
}
}
Как вы можете видеть в примере выше, функция переданная методу extend
должна
вернуть реализацию Illuminate\Contracts\Auth\Guard
. Этот интерфейс содержит
несколько методов, которые вам нужно реализовать, чтобы определить пользовательского стража.
После определения пользовательского стража, вы можете его в конфигурации guards
для файла auth.php
:
'guards' => [
'api' => [
'driver' => 'jwt',
'provider' => 'users',
],
],
Замыкание запросов защитников
Самый простой способ реализовать пользовательскую, основанную на HTTP, систему
аутентификации — это использовать метод Auth::viaRequest
. Он позволит вам
быстро определить ваш процесс аутентификации, используя Замыкание.
Для начала, вызовите метод Auth::viaRequest
внутри метода boot
вашего AuthServiceProvider
. Метод viaRequest
принимает название
драйвера аутентификации в качестве первого аргумента. Название может быть любой строкой,
которая описывает вашего пользовательского стража. Второй аргумент, который передаётся в
метод, должен быть замыканием, которое получает входящий HTTP запрос и возвращает
экземпляр пользователя, или если аутентификация провалилась, null
:
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
/**
* Register any application authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Auth::viaRequest('custom-token', function ($request) {
return User::where('token', $request->token)->first();
});
}
После того, как ваш драйвер аутентификации был определён,
вы будете использовать его внутри файла auth.php
в качестве соответсвенно стража для пункта guards
:
'guards' => [
'api' => [
'driver' => 'custom-token',
],
],
Добавление пользовательских User провайдеров
Если вы не используете традиционную реляционную базу данных для хранения
пользователей, вам будет необходимо расширить Laravel вашим собственным
провайдером аутентификации пользователя. Мы будем использовать метод
provider
для фасада Auth
, чтобы определить
пользовательский провайдер:
<?php
namespace App\Providers;
use Illuminate\Support\Facades\Auth;
use App\Extensions\RiakUserProvider;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* Register any application authentication / authorization services.
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
Auth::provider('riak', function ($app, array $config) {
// Return an instance of Illuminate\Contracts\Auth\UserProvider...
return new RiakUserProvider($app->make('riak.connection'));
});
}
}
Псоле регистрации провайдера используя метод provider
, вы можете переключиться
на новый провайдер в файле конфигурации auth.php
. Во-первых, определим
provider
, который использует новый драйвер:
'providers' => [
'users' => [
'driver' => 'riak',
],
],
Наконец, вы можете использовать этот провайде в вашей конфигурации guards
:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
],
Контракт User провайдера
Реализации Illuminate\Contracts\Auth\UserProvider
несут ответственность только
за получение реализации Illuminate\Contracts\Auth\Authenticatable
из постоянной
системы хранения, таких как MySQL, Riak и других. Эти два интерфейса позволяют продолжить работу
механизмам аутентификации Ларавел вне зависимости от того, какие данные пользователя хранятся, или
какой тип класса использован для их представления.
Давайте взглянем на контракт Illuminate\Contracts\Auth\UserProvider
:
<?php
namespace Illuminate\Contracts\Auth;
interface UserProvider {
public function retrieveById($identifier);
public function retrieveByToken($identifier, $token);
public function updateRememberToken(Authenticatable $user, $token);
public function retrieveByCredentials(array $credentials);
public function validateCredentials(Authenticatable $user, array $credentials);
}
Функция retrieveById
обычно получает ключ, представляющий пользователя, такой
как автоматическое увеличение идентификатора из базы данных MySQL. Реализация
Authenticatable
соединяет ID, который должен быть получен и возвращен методом.
Функция retrieveByToken
получает пользователя по их уникальному идентификатору
$identifier
и токену "запомнить меня", хранящихся в поле remember_token
.
Как и в случае с предыдущим методом, должна быть возвращена реализация Authenticatable
.
Метод updateRememberToken
обновляет $user
поле remember_token
новым $token
. Новый токен приписывает для успешного входа с пометко "запомнить меня",
или когда пользователь выходит из системы.
Метод retrieveByCredentials
получает массив данных передаваемых в метод
Auth::attempt
при попытке входа в прлиожение. Метод должен сделать запрос
в постоянное хранилище для того, чтобы найти соответствующую запись пользователя с этими
данными. Обычно, метод выполнит запрос с условием "where" для $credentials['username']
.
После чего метод должен вернуть реализацию Authenticatable
. Этот метод не должен
пытаться делать любую валидацию пароля или аутентификации.
Метод validateCredentials
должен сравнивать представленные $user
с $credentials
для аутентификации пользователя. Например, этот метод вероятно должен
использовать Hash::check
, чтобы сравнить значение $user->getAuthPassword()
со значением $credentials['password']
. Этот метод должен вернуть true
или
false
в зависимости от того, валидный пароль или нет.
Контракт Authenticatable
Теперь мы исследовали каждый из методов UserProvider
, давайте взглянем на контракт
Authenticatable
. Стоит вспомнить, что провайдер должен вернуть реализации интерфейса
из методов retrieveById
, retrieveByToken
,
и retrieveByCredentials
:
<?php
namespace Illuminate\Contracts\Auth;
interface Authenticatable {
public function getAuthIdentifierName();
public function getAuthIdentifier();
public function getAuthPassword();
public function getRememberToken();
public function setRememberToken($value);
public function getRememberTokenName();
}
Это простой интерфейс. Метод getAuthIdentifierName
должен вернуть
имя поля с отметкой "первичный ключ" для пользователя, а метод getAuthIdentifier
должен вернуть само значение первичного ключа. Для MySQL это будет автоматически увеличивающийся
первичный ключ. getAuthPassword
должен вернуть захешированный пароль пользователя.
Этот интерфейс позволяет системе аутентификации работать с любым классом пользователя,
вне зависимости от того, какую ORM или какой слой работы с бд вы используете. По умолчанию,
Ларавел включает класс User
в папке app
, который реализует этот
интерфейс, поэтому вы можете обратиться к этому класса для примера реализации.
События
В процессе аутентификации Ларавел абращается к большоми числу событий. Вы можете прикрепить
слушателя к этим событиям в вашем EventServiceProvider
:
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
'Illuminate\Auth\Events\Registered' => [
'App\Listeners\LogRegisteredUser',
],
'Illuminate\Auth\Events\Attempting' => [
'App\Listeners\LogAuthenticationAttempt',
],
'Illuminate\Auth\Events\Authenticated' => [
'App\Listeners\LogAuthenticated',
],
'Illuminate\Auth\Events\Login' => [
'App\Listeners\LogSuccessfulLogin',
],
'Illuminate\Auth\Events\Failed' => [
'App\Listeners\LogFailedLogin',
],
'Illuminate\Auth\Events\Logout' => [
'App\Listeners\LogSuccessfulLogout',
],
'Illuminate\Auth\Events\Lockout' => [
'App\Listeners\LogLockout',
],
'Illuminate\Auth\Events\PasswordReset' => [
'App\Listeners\LogPasswordReset',
],
];