518d71e81f
Именованные лимитеры auth-login/auth-2fa/auth-password (perMinute 20 by IP) в AppServiceProvider; throttle-middleware на login/forgot/reset/2fa-verify/recovery в web.php. Закрывает per-IP объёмный перебор. Pest tests/Feature/Auth 97/97 GREEN. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
34 lines
1.5 KiB
PHP
34 lines
1.5 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
use Illuminate\Foundation\Testing\DatabaseTransactions;
|
||
use Illuminate\Support\Facades\Notification;
|
||
|
||
uses(DatabaseTransactions::class);
|
||
|
||
/**
|
||
* Route-level rate-limit (Laravel Throttle) на auth-эндпоинтах.
|
||
* Закрывает P1 go-live аудита: per-IP объёмный предел поверх прикладного
|
||
* per-credential rate-limit в контроллерах.
|
||
*
|
||
* Бьём по forgot с РАЗНЫМИ unknown-email: контроллерный per-email лимит (5)
|
||
* не срабатывает (разные ключи) → unified 200. Единственный ограничитель —
|
||
* route-throttle по IP (лимитер auth-password, 20/мин). 21-й запрос → 429 от
|
||
* middleware, что и доказывает: ограничение пришло от route-throttle, а не от
|
||
* контроллера.
|
||
*/
|
||
test('route-throttle: 21-й POST /api/auth/forgot с одного IP отбивается middleware 429', function () {
|
||
Notification::fake();
|
||
|
||
// 20 запросов с разными unknown-email — каждый 200 (per-email лимит не задет).
|
||
for ($i = 1; $i <= 20; $i++) {
|
||
$this->postJson('/api/auth/forgot', ['email' => "vol{$i}@example.ru"])
|
||
->assertOk();
|
||
}
|
||
|
||
// 21-й с одного IP → 429 от throttle-middleware (до контроллера).
|
||
$this->postJson('/api/auth/forgot', ['email' => 'vol21@example.ru'])
|
||
->assertStatus(429);
|
||
});
|