From dd368e3c489da3fd7aea291ae088b95217b0ebc0 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Wed, 19 Nov 2025 14:52:07 +0700 Subject: [PATCH] feat: custom login --- app/Filament/Pages/CustomLogin.php | 153 ++++++++++++++++++ .../Filament/DashboardPanelProvider.php | 3 +- 2 files changed, 155 insertions(+), 1 deletion(-) create mode 100644 app/Filament/Pages/CustomLogin.php diff --git a/app/Filament/Pages/CustomLogin.php b/app/Filament/Pages/CustomLogin.php new file mode 100644 index 0000000..2aa3934 --- /dev/null +++ b/app/Filament/Pages/CustomLogin.php @@ -0,0 +1,153 @@ +components([ + TextInput::make('login') + ->label('Nama Pengguna atau Alamat Surel') + ->placeholder('johndoe@puskesmas.com') + ->required() + ->autocomplete(false) + ->autofocus(), + + TextInput::make('password') + ->label('Kata Sandi') + ->placeholder('********') + ->password() + ->revealable(filament()->arePasswordsRevealable()) + ->required() + ->autocomplete(false) + ->extraInputAttributes(['tabindex' => 2]) + ->hint( + filament()->hasPasswordReset() + ? new HtmlString(Blade::render('{{ __(\'filament-panels::auth/pages/login.actions.request_password_reset.label\') }}')) + : null + ), + ]); + } + + protected function getCredentialsFromFormData(#[SensitiveParameter] array $data): array + { + $loginType = filter_var($data['login'], FILTER_VALIDATE_EMAIL) ? 'email' : 'username'; + + return [ + $loginType => $data['login'], + 'password' => $data['password'], + ]; + } + + public function authenticate(): ?LoginResponse + { + try { + $this->rateLimit(5); + } catch (TooManyRequestsException $exception) { + $this->getRateLimitedNotification($exception)?->send(); + + return null; + } + + $data = $this->form->getState(); + + /** @var SessionGuard $authGuard */ + $authGuard = Filament::auth(); + + $authProvider = $authGuard->getProvider(); + /** @phpstan-ignore-line */ + $credentials = $this->getCredentialsFromFormData($data); + + $user = $authProvider->retrieveByCredentials($credentials); + + if ((! $user) || (! $authProvider->validateCredentials($user, $credentials))) { + $this->userUndertakingMultiFactorAuthentication = null; + + $this->fireFailedEvent($authGuard, $user, $credentials); + $this->throwFailureValidationException(); + } + + if ( + filled($this->userUndertakingMultiFactorAuthentication) && + (decrypt($this->userUndertakingMultiFactorAuthentication) === $user->getAuthIdentifier()) + ) { + $this->multiFactorChallengeForm->validate(); + } else { + foreach (Filament::getMultiFactorAuthenticationProviders() as $multiFactorAuthenticationProvider) { + if (! $multiFactorAuthenticationProvider->isEnabled($user)) { + continue; + } + + $this->userUndertakingMultiFactorAuthentication = encrypt($user->getAuthIdentifier()); + + if ($multiFactorAuthenticationProvider instanceof HasBeforeChallengeHook) { + $multiFactorAuthenticationProvider->beforeChallenge($user); + } + + break; + } + + if (filled($this->userUndertakingMultiFactorAuthentication)) { + $this->multiFactorChallengeForm->fill(); + + return null; + } + } + + if (! $authGuard->attemptWhen($credentials, function (Authenticatable $user): bool { + if (! ($user instanceof FilamentUser)) { + return true; + } + + return $user->canAccessPanel(Filament::getCurrentOrDefaultPanel()); + }, $data['remember'] ?? false)) { + $this->fireFailedEvent($authGuard, $user, $credentials); + $this->throwFailureValidationException(); + } + + session()->regenerate(); + + Notification::make() + ->title('Berhasil Masuk') + ->body('Selamat datang, '.$user->name.'!') + ->success() + ->send(); + + return app(LoginResponse::class); + } + + protected function throwFailureValidationException(): never + { + Notification::make() + ->title('Gagal Masuk') + ->body('Alamat surel, nama pengguna atau kata sandi salah. Silakan coba lagi.') + ->danger() + ->send(); + + throw ValidationException::withMessages([]); + } +} diff --git a/app/Providers/Filament/DashboardPanelProvider.php b/app/Providers/Filament/DashboardPanelProvider.php index 53f08a4..22d50f1 100644 --- a/app/Providers/Filament/DashboardPanelProvider.php +++ b/app/Providers/Filament/DashboardPanelProvider.php @@ -2,6 +2,7 @@ namespace App\Providers\Filament; +use App\Filament\Pages\CustomLogin; use Filament\Http\Middleware\Authenticate; use Filament\Http\Middleware\AuthenticateSession; use Filament\Http\Middleware\DisableBladeIconComponents; @@ -28,7 +29,7 @@ public function panel(Panel $panel): Panel ->default() ->id('dashboard') ->path('dashboard') - ->login() + ->login(CustomLogin::class) ->colors([ 'primary' => Color::Blue, ])