Middle: питання на співбесіді з теми «Автентифікація»
Питання з реальних співбесід з відповідями: Laravel і PHP, бази даних, JavaScript і фронтенд, Git, Docker, API, безпека й архітектура. Тими самими темами, що й тести.
4 питання
Це різні рівні автентифікації:
- Breeze - стартовий набір UI: реєстрація/вхід/скидання пароля на Blade+Livewire або React/Vue. Для швидкого старту.
- Fortify - headless-бекенд автентифікації (без UI): логіка реєстрації, 2FA, скидання пароля. Під ним працює Breeze/Jetstream.
- Sanctum - легка автентифікація для SPA (через cookie) та простих API-токенів. Дефолт для більшості API.
- Passport - повноцінний OAuth2-сервер: видача access/refresh токенів стороннім клієнтам. Обирають, коли потрібен саме OAuth2.
Правило: SPA чи мобільний застосунок → Sanctum; «увійти через наш сервіс» для третіх сторін → Passport.
Sanctum дає два режими:
1. API-токени - модель випускає токен, який клієнт шле в заголовку Authorization: Bearer ...:
$token = $user->createToken('mobile', ['posts:read'])->plainTextToken;
Route::middleware('auth:sanctum')->get('/user', fn (Request $r) => $r->user());
2. SPA-автентифікація - для односторінкових застосунків на тому ж домені використовує звичайні сесійні cookie + CSRF (без зберігання токенів у JS, що безпечніше).
Токени підтримують abilities (scopes): $user->tokenCan('posts:read'). Трейт HasApiTokens додає tokens()-зв'язок і createToken().
Автентифікація в Laravel тримається на двох поняттях з config/auth.php.
- Гард визначає, як користувача впізнають у запиті:
session- за сесією й cookie,sanctum- ще й за токеном у заголовку. - Провайдер визначає, звідки користувача беруть: зазвичай Eloquent-модель
Userчи таблиця бази.
'guards' => [
'web' => ['driver' => 'session', 'provider' => 'users'],
'admin' => ['driver' => 'session', 'provider' => 'admins'],
],
'providers' => [
'users' => ['driver' => 'eloquent', 'model' => App\Models\User::class],
'admins' => ['driver' => 'eloquent', 'model' => App\Models\Admin::class],
],
Коли другий гард виправданий: коли це справді інші люди в іншій таблиці - адміністратори окремо від клієнтів, з окремим входом і сесією.
Route::middleware('auth:admin')->group(fn () => /* ... */);
Auth::guard('admin')->attempt($credentials);
Коли не потрібен: якщо різниця лише в правах. «Адмін - теж користувач, але з роллю» - це авторизація (ролі, політики), а не другий гард. Зайвий гард подвоює логіку входу, скидання пароля й верифікації пошти.
Обмежити кількість невдалих спроб - за ключем, що поєднує email та IP.
public function authenticate(): void
{
$key = Str::transliterate(Str::lower($this->input('email'))) . '|' . $this->ip();
if (RateLimiter::tooManyAttempts($key, 5)) {
throw ValidationException::withMessages([
'email' => __('auth.throttle', ['seconds' => RateLimiter::availableIn($key)]),
]);
}
if (! Auth::attempt($this->only('email', 'password'))) {
RateLimiter::hit($key);
throw ValidationException::withMessages(['email' => __('auth.failed')]);
}
RateLimiter::clear($key);
}
Чому саме такий ключ:
- Лише IP - заблокує цілий офіс за NAT, а зловмисник із сотнею адрес обійде.
- Лише email - будь-хто зможе заблокувати вхід чужому акаунту, просто вводячи неправильний пароль.
- Email + IP гальмує перебір конкретного акаунта з конкретної адреси.
Що ще допомагає:
- однакове повідомлення «Невірний email або пароль» - щоб не підказувати, які email зареєстровані;
- не блокувати акаунт назавжди після N спроб - це інструмент для атаки на доступність;
- двофакторна автентифікація, після якої перебір пароля сам по собі нічого не дає.
Стартові набори Laravel 13 вже обмежують спроби входу. Якщо застосунок за проксі (Cloudflare), перевірте довірені проксі - інакше всі запити матимуть IP проксі.