mirror of
https://github.com/filamentphp/filament.git
synced 2026-09-24 15:42:09 +08:00
Merge pull request #17121 from filamentphp/fix/login-failed-event
fix: Login failed event
This commit is contained in:
@@ -27,14 +27,17 @@ use Filament\Schemas\Components\Utilities\Get;
|
||||
use Filament\Schemas\Schema;
|
||||
use Filament\Support\Enums\Alignment;
|
||||
use Filament\View\PanelsRenderHook;
|
||||
use Illuminate\Auth\Events\Failed;
|
||||
use Illuminate\Auth\SessionGuard;
|
||||
use Illuminate\Contracts\Auth\Authenticatable;
|
||||
use Illuminate\Contracts\Auth\Guard;
|
||||
use Illuminate\Contracts\Support\Htmlable;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Support\Facades\Blade;
|
||||
use Illuminate\Support\HtmlString;
|
||||
use Illuminate\Validation\ValidationException;
|
||||
use Livewire\Attributes\Locked;
|
||||
use SensitiveParameter;
|
||||
|
||||
/**
|
||||
* @property-read Action $registerAction
|
||||
@@ -74,7 +77,10 @@ class Login extends SimplePage
|
||||
|
||||
$data = $this->form->getState();
|
||||
|
||||
$authProvider = Filament::auth()->getProvider(); /** @phpstan-ignore-line */
|
||||
/** @var SessionGuard $authGuard */
|
||||
$authGuard = Filament::auth();
|
||||
|
||||
$authProvider = $authGuard->getProvider(); /** @phpstan-ignore-line */
|
||||
$credentials = $this->getCredentialsFromFormData($data);
|
||||
|
||||
$user = $authProvider->retrieveByCredentials($credentials);
|
||||
@@ -82,6 +88,7 @@ class Login extends SimplePage
|
||||
if ((! $user) || (! $authProvider->validateCredentials($user, $credentials))) {
|
||||
$this->userUndertakingMultiFactorAuthentication = null;
|
||||
|
||||
$this->fireFailedEvent($authGuard, $user, $credentials);
|
||||
$this->throwFailureValidationException();
|
||||
}
|
||||
|
||||
@@ -112,9 +119,6 @@ class Login extends SimplePage
|
||||
}
|
||||
}
|
||||
|
||||
/** @var SessionGuard $authGuard */
|
||||
$authGuard = Filament::auth();
|
||||
|
||||
if (! $authGuard->attemptWhen($credentials, function (Authenticatable $user): bool {
|
||||
if (! ($user instanceof FilamentUser)) {
|
||||
return true;
|
||||
@@ -122,6 +126,7 @@ class Login extends SimplePage
|
||||
|
||||
return $user->canAccessPanel(Filament::getCurrentOrDefaultPanel());
|
||||
}, $data['remember'] ?? false)) {
|
||||
$this->fireFailedEvent($authGuard, $user, $credentials);
|
||||
$this->throwFailureValidationException();
|
||||
}
|
||||
|
||||
@@ -144,6 +149,14 @@ class Login extends SimplePage
|
||||
->danger();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $credentials
|
||||
*/
|
||||
protected function fireFailedEvent(Guard $guard, ?Authenticatable $user, #[SensitiveParameter] array $credentials): void
|
||||
{
|
||||
event(app(Failed::class, ['guard' => property_exists($guard, 'name') ? $guard->name : '', 'user' => $user, 'credentials' => $credentials]));
|
||||
}
|
||||
|
||||
protected function throwFailureValidationException(): never
|
||||
{
|
||||
throw ValidationException::withMessages([
|
||||
@@ -352,7 +365,7 @@ class Login extends SimplePage
|
||||
* @param array<string, mixed> $data
|
||||
* @return array<string, mixed>
|
||||
*/
|
||||
protected function getCredentialsFromFormData(array $data): array
|
||||
protected function getCredentialsFromFormData(#[SensitiveParameter] array $data): array
|
||||
{
|
||||
return [
|
||||
'email' => $data['email'],
|
||||
|
||||
@@ -4,6 +4,8 @@ use Filament\Auth\Pages\Login;
|
||||
use Filament\Facades\Filament;
|
||||
use Filament\Tests\Fixtures\Models\User;
|
||||
use Filament\Tests\TestCase;
|
||||
use Illuminate\Auth\Events\Failed;
|
||||
use Illuminate\Support\Facades\Event;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
use function Filament\Tests\livewire;
|
||||
@@ -61,6 +63,8 @@ it('can redirect unauthenticated app requests', function (): void {
|
||||
});
|
||||
|
||||
it('cannot authenticate with incorrect credentials', function (): void {
|
||||
Event::fake([Failed::class]);
|
||||
|
||||
$userToAuthenticate = User::factory()->create();
|
||||
|
||||
livewire(Login::class)
|
||||
@@ -72,9 +76,30 @@ it('cannot authenticate with incorrect credentials', function (): void {
|
||||
->assertHasFormErrors(['email']);
|
||||
|
||||
$this->assertGuest();
|
||||
|
||||
Event::assertDispatched(function (Failed $event) use ($userToAuthenticate) {
|
||||
if ($event->guard !== 'web') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $event->user->is($userToAuthenticate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($event->credentials !== [
|
||||
'email' => $userToAuthenticate->email,
|
||||
'password' => 'incorrect-password',
|
||||
]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
it('cannot authenticate on unauthorized panel', function (): void {
|
||||
Event::fake([Failed::class]);
|
||||
|
||||
$userToAuthenticate = User::factory()->create();
|
||||
|
||||
Filament::setCurrentPanel('custom');
|
||||
@@ -88,6 +113,25 @@ it('cannot authenticate on unauthorized panel', function (): void {
|
||||
->assertHasFormErrors(['email']);
|
||||
|
||||
$this->assertGuest();
|
||||
|
||||
Event::assertDispatched(function (Failed $event) use ($userToAuthenticate) {
|
||||
if ($event->guard !== 'web') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (! $event->user->is($userToAuthenticate)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($event->credentials !== [
|
||||
'email' => $userToAuthenticate->email,
|
||||
'password' => 'password',
|
||||
]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
});
|
||||
|
||||
it('can throttle authentication attempts', function (): void {
|
||||
|
||||
Reference in New Issue
Block a user