mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
fix: Login with username (instead of email) (#19387)
This commit is contained in:
@@ -78,10 +78,6 @@ class Login extends SimplePage
|
||||
|
||||
$data = $this->form->getState();
|
||||
|
||||
if ($this->isLoginRateLimited($data['email'])) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var SessionGuard $authGuard */
|
||||
$authGuard = Filament::auth();
|
||||
|
||||
@@ -164,26 +160,6 @@ class Login extends SimplePage
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function isLoginRateLimited(string $email): bool
|
||||
{
|
||||
$rateLimitingKey = 'filament-login:' . sha1(request()->ip() . '|' . $email);
|
||||
|
||||
if (RateLimiter::tooManyAttempts($rateLimitingKey, maxAttempts: 5)) {
|
||||
$this->getRateLimitedNotification(new TooManyRequestsException(
|
||||
static::class,
|
||||
'authenticate',
|
||||
request()->ip(),
|
||||
RateLimiter::availableIn($rateLimitingKey),
|
||||
))?->send();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
RateLimiter::hit($rateLimitingKey);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected function getRateLimitedNotification(TooManyRequestsException $exception): ?Notification
|
||||
{
|
||||
return Notification::make()
|
||||
|
||||
@@ -215,61 +215,6 @@ it('can fill the login form, authenticate, and redirect to the dashboard in the
|
||||
->assertNoAccessibilityIssues();
|
||||
});
|
||||
|
||||
it('can throttle login attempts per IP and email', function (): void {
|
||||
$this->assertGuest();
|
||||
|
||||
$userToAuthenticate = User::factory()->create();
|
||||
|
||||
// Clear the IP-only rate limiter between attempts to isolate the
|
||||
// IP+email rate limit.
|
||||
$clearIpRateLimiter = function (): void {
|
||||
RateLimiter::clear('livewire-rate-limiter:' . sha1(Login::class . '|authenticate|' . request()->ip()));
|
||||
};
|
||||
|
||||
foreach (range(1, 5) as $i) {
|
||||
$clearIpRateLimiter();
|
||||
|
||||
livewire(Login::class)
|
||||
->fillForm([
|
||||
'email' => $userToAuthenticate->email,
|
||||
'password' => 'password',
|
||||
])
|
||||
->call('authenticate');
|
||||
|
||||
$this->assertAuthenticated();
|
||||
|
||||
auth()->logout();
|
||||
}
|
||||
|
||||
$clearIpRateLimiter();
|
||||
|
||||
// The 6th attempt from the same IP + email should be rate limited
|
||||
livewire(Login::class)
|
||||
->fillForm([
|
||||
'email' => $userToAuthenticate->email,
|
||||
'password' => 'password',
|
||||
])
|
||||
->call('authenticate')
|
||||
->assertNotified();
|
||||
|
||||
$this->assertGuest();
|
||||
|
||||
$clearIpRateLimiter();
|
||||
|
||||
// A different email from the same IP should not be affected
|
||||
$secondUser = User::factory()->create();
|
||||
|
||||
livewire(Login::class)
|
||||
->fillForm([
|
||||
'email' => $secondUser->email,
|
||||
'password' => 'password',
|
||||
])
|
||||
->call('authenticate')
|
||||
->assertRedirect(Filament::getUrl());
|
||||
|
||||
$this->assertAuthenticatedAs($secondUser);
|
||||
});
|
||||
|
||||
it('does not lock out a user when an attacker exhausts login attempts from a different IP', function (): void {
|
||||
$this->assertGuest();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user