Laravel має чудову нестандартну систему авторизації, але, безсумнівно, нам потрібно налаштувати речі тут і там. Для деяких з них немає необхідності шукати зовнішні пакети або писати багато власного коду, давайте дослідимо, які цікаві здібності ховаються під капотом Auth.
Ми всі, напевно, знаємо метод Auth :: routes (), який походить від пакету Laravel UI (до Laravel 7 він був включений в ядро).
Але чи знаєте ви, що він може приймати масив параметрів для ввімкнення / вимкнення певних маршрутів авторизації?
Починаючи з Laravel 7, ось можливі параметри зі значеннями за замовчуванням:
Auth::routes([ 'login' => true, 'logout' => true, 'register' => true, 'reset' => true, // for resetting passwords 'confirm' => false, // for additional password confirmations 'verify' => false, // for email verification ]);
Ці параметри просто вмикають або вимикають деякі маршрути.
Щоб зрозуміти, як вони працюють, ви можете подивитися файл AuthRouteMethods в Laravel UI:
return function ($options = []) { // Login Routes... if ($options['login'] ?? true) { $this->get('login', 'Auth\LoginController@showLoginForm')->name('login'); $this->post('login', 'Auth\LoginController@login'); } // Logout Routes... if ($options['logout'] ?? true) { $this->post('logout', 'Auth\LoginController@logout')->name('logout'); } // Registration Routes... if ($options['register'] ?? true) { $this->get('register', 'Auth\RegisterController@showRegistrationForm')->name('register'); $this->post('register', 'Auth\RegisterController@register'); } // Password Reset Routes... if ($options['reset'] ?? true) { $this->resetPassword(); } // Password Confirmation Routes... if ($options['confirm'] ?? class_exists($this->prependGroupNamespace('Auth\ConfirmPasswordController'))) { $this->confirmPassword(); } // Email Verification Routes... if ($options['verify'] ?? false) { $this->emailVerification(); } };
Офіційна документація визначає цей Порада, як основний використання Laravel UI:
php artisan ui vue --aut
Але що, якщо вам не потрібен візуальний інтерфейс? Що робити, якщо ви створюєте лише проект, заснований на API, і у вас немає фронт-енду на стороні Laravel?
Ви все ще можете використовувати Laravel Auth та його контролери. Встановіть пакет Laravel UI та запустіть ось таку команду:
php artisan ui:controllers
це буде генерувати лише вміст app / Http / Controllers / Auth, тому для їх використання вам не потрібні файли Blade / Vue.
Подивіться реалізацію цієї команди Artisan у репозиторії Github.
Ви коли-небудь підтримували сховище Github і намагалися змінити його налаштування доступу? Потім Github просить вас знову ввести пароль знову, лише щоб переконатися, що це ви.
Починаючи з Laravel 6.2, ми також маємо таку особливість у фреймворку.
Все, що вам потрібно зробити, це додати проміжне програмне забезпечення, яке називається password.confirm, до маршрутів, які ви хочете захистити.
Route::get('/secrets', 'SecretsController@show')->middleware('password.confirm');
Цитата Dries Vints з офіційної статті про випуск функцій:
"Якщо ви спробуєте отримати доступ до маршруту, вам буде запропоновано підтвердити свій пароль, подібний до того, що ви могли бачити в інших програмах, таких як GitHub.
Підтвердження пароля зберігатиме позначку часу в сеансі користувача, яка триває три години за замовчуванням, тому користувачам не доведеться вводити свій пароль протягом цього періоду знову.
Ви можете налаштувати цю тривалість, використовуючи нову опцію налаштування password_timeout у файлі конфігурації auth."
Починаючи з Laravel 5.6, ми маємо окремий метод автоматичного виходу з будь-яких інших пристроїв або браузерів, які увійшли в систему за допомогою нашого облікового запису:
Auth::logoutOtherDevices($password);
Типовим використанням цього є вихід із інших пристроїв при успішному вході поточного пристрою. Для цього ми замінюємо метод, автентифікований () з Trait AuthenticatesUsers.php, і поміщаємо його в app / Http / Controllers / Auth / LoginController.php:
protected function authenticated(Request $request, $user) { \Auth::logoutOtherDevices(request('password')); }
Також не забудьте активувати один проміжний файл AuthenticateSession у файлі app / Http / Kernel.php, який за замовчуванням коментується:
protected $middlewareGroups = [ 'web' => [ \App\Http\Middleware\EncryptCookies::class, \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class, \Illuminate\Session\Middleware\StartSession::class, // \Illuminate\Session\Middleware\AuthenticateSession::class, \Illuminate\View\Middleware\ShareErrorsFromSession::class, \App\Http\Middleware\VerifyCsrfToken::class, \Illuminate\Routing\Middleware\SubstituteBindings::class, ],
За замовчуванням і Laravel LoginController, і RegisterController мають однакові властивості:
class RegisterController extends Controller { protected $redirectTo = RouteServiceProvider::HOME;
Тож ви можете вказати, на яку URL-адресу переспрямовувати після успішного входу / реєстрації. Значення за замовчуванням знаходиться в app / Providers / RouteServiceProvider.php:
class RouteServiceProvider extends ServiceProvider { public const HOME = '/home';
Як ви можете його налаштувати?
По-перше, ви можете змінити значення властивості $ redirectTo на якусь іншу константу, а може бути окремо для Входу та Реєстрації.
Але що, якщо у вас є більш складна логіка динамічного перенаправлення, яка, наприклад, залежить від ролі користувача?
Ви можете створити метод у цих контролерах авторизації, викликати його redirectTo () та вказати свої умови всередині. Цей метод замінить будь-які значення властивості $ redirectTo.
Дивимось приклад:
class RegisterController extends Controller { protected $redirectTo = RouteServiceProvider::HOME; protected function redirectTo() { if (auth()->user()->role_id == 1) { return '/admin'; } return '/home'; }
Що робити, якщо вам потрібно створити одного нового користувача, а у вас немає готової форми реєстрації?
Просто відкрийте Laravel Tinker у своєму терміналі:
php artisan tinker
Якщо ви не знайомі з Tinker, це інструмент командного рядка для запуску будь-якого коду Laravel / PHP. Отже, всередині цього ви можете легко створити користувача, набравши цю промовисту команду та натиснувши Enter:
\App\User::create(['name' => 'Admin', 'email' => 'admin@admin.com', 'password' => bcrypt('somesecurepassword')]);
Але що, якщо вам потрібно створити багато користувачів для тестування, наприклад, 10, 100 або 1000? Немає проблем, ми можемо використовувати заводський клас, який за замовчуванням поставляється з Laravel, в database/factories/UserFactory.php:
$factory->define(User::class, function (Faker $faker) { return [ 'name' => $faker->name, 'email' => $faker->unique()->safeEmail, 'email_verified_at' => now(), 'password' => '$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi', // password 'remember_token' => Str::random(10), ]; });
Це значення за замовчуванням для “фейкового” користувача, якого ми можемо створити. Для цього ми створимо файл Seeder:
php artisan make:seeder UsersSeeder
Потім ми відкриваємо створений файл бази даних / seed / UsersSeeder.php і заповнюємо метод run () таким чином:
public function run() { // This will create 100 users factory(App\User::class, 100)->create(); }
Щоб це запустити, нам потрібно виконати наступну команду:
php artisan db:seed --class=UsersSeeder
Ви можете прочитати більше про сіди баз даних в офіційній документації Laravel.
За замовчуванням користувачі Laravel автентифікуються за допомогою електронної пошти та пароля. Але що, якщо ваш ідентифікатор - не електронна пошта? Якесь ім'я користувача, наприклад.
Ви можете легко змінити це, перевизначивши один метод із ознаки AuthenticatesUsers.php.
Ось значення за замовчуванням:
trait AuthenticatesUsers { // ... other methods public function username() { return 'email'; }
Ви можете скопіювати це у свій LoginController.php і просто змінити значення:
class LoginController extends Controller { use AuthenticatesUsers; // ... other methods public function username() { return 'username'; } }
Давайте зробимо ще один крок далі. Що робити, якщо ваші користувачі можуть увійти за допомогою електронної пошти АБО ім’я користувача? Тож є поле введення під назвою «Електронна адреса / ім’я користувача», і вони можуть вводити те чи інше.
Давайте додамо «фокус» до того самого методу username () зверху. Ми перевіряємо, чи введений рядок є електронною поштою, інакше ми розглядаємо його як ім’я користувача. Ця перевірка є функцією PHP, навіть не Laravel.
class LoginController extends Controller { // ... public function username() { return filter_var(request('email'), FILTER_VALIDATE_EMAIL) ? 'email' : 'username'; } }
Примітка: не забувайте, що у формі для входу вам потрібно змінити тип введення type="email" на type="text".
Якщо ви спробуєте ввійти з недійсними обліковими даними більше п’яти разів протягом однієї хвилини, вас заблокують із повідомленням Забагато спроб входу. Повторіть спробу через X секунд.
Цей блок буде активним протягом 1 хвилини, і він унікальний для імені користувача / електронної пошти користувача та його IP-адреси.
Ви можете налаштувати ці параметри:
Кількість недійсних спроб протягом хвилини (п’ять спроб за замовчуванням)
Скільки хвилин для блокування входів (за замовчуванням 1 хвилина)
Ці два параметри знаходяться всередині Trait ThrottlesLogins:
trait ThrottlesLogins { // ... other methods /** * Get the maximum number of attempts to allow. * * @return int */ public function maxAttempts() { return property_exists($this, 'maxAttempts') ? $this->maxAttempts : 5; } /** * Get the number of minutes to throttle for. * * @return int */ public function decayMinutes() { return property_exists($this, 'decayMinutes') ? $this->decayMinutes : 1; } }
Отже, щоб замінити їх, ви можете вказати властивості всередині вашого LoginController:
class LoginController extends Controller { protected $maxAttempts = 3; // Default is 5 protected $decayMinutes = 2; // Default is 1 // ... }
За замовчуванням нещодавно зареєстрований користувач автоматично входить у систему та перенаправляється на домашню сторінку.
Якщо ви хочете вимкнути це і натомість показати сторінку «вдалої реєстрації», не створюючи автоматично сеанс користувача, ось що ви можете зробити.
Оригінальний метод реєстрації знаходиться всередині Trait RegistersUsers:
trait RegistersUsers { public function register(Request $request) { $this->validator($request->all())->validate(); event(new Registered($user = $this->create($request->all()))); $this->guard()->login($user); if ($response = $this->registered($request, $user)) { return $response; } return $request->wantsJson() ? new Response('', 201) : redirect($this->redirectPath()); }
Отже, ваша мета - перевизначити його в RegisterController і повернути переспрямування на вашу нову сторінку, а не входити в систему:
class RegisterController extends Controller { use RegistersUsers; public function register(Request $request) { $this->validator($request->all())->validate(); event(new Registered($user = $this->create($request->all()))); return redirect()->route('your_success_page_route_name'); }
Що робити, якщо вам потрібна додаткова перевірка, крім електронної пошти та пароля за замовчуванням? Наприклад, ви хочете перевірити, чи користувач активний чи не заборонений.
Ви можете додати додаткові елементи до масиву облікових даних, який визначено в ознаці AuthenticatesUsers:
trait AuthenticatesUsers { // ... protected function credentials(Request $request) { return $request->only($this->username(), 'password'); }
Ви просто перевизначаєте це в LoginController і додаєте все, що завгодно:
class LoginController extends Controller { // ... protected function credentials(Request $request) { return $request->only($this->username(), 'password') + ['is_active' => 1]; }
Примітка: це цікава підказка, але я б порадив вам зробити таку додаткову перевірку в окремому проміжному програмному забезпеченні, тоді ви можете надати користувачеві більш чітке повідомлення про помилку, замість помилки облікових даних за замовчуванням.
Ось і все, це короткі поради, але є ще багато чого, що можна розширити за допомогою власного коду та зовнішніх пакетів. Тож, слідкуйте за новинами на цю тему!