|
10 | 10 | use Visualbuilder\Filament2fa\TwoFactorAuthResponse;
|
11 | 11 | use Visualbuilder\Filament2fa\Contracts\TwoFactorAuthenticatable;
|
12 | 12 | use Illuminate\Support\Facades\Crypt;
|
| 13 | +use Illuminate\Contracts\Auth\Authenticatable; |
13 | 14 |
|
14 | 15 | class Login extends BaseLogin
|
15 | 16 | {
|
16 | 17 | public function authenticate(): null|TwoFactorAuthResponse|LoginResponse
|
17 | 18 | {
|
18 |
| - try { |
19 |
| - $this->rateLimit(5); |
20 |
| - } catch (TooManyRequestsException $exception) { |
21 |
| - $this->getRateLimitedNotification($exception)?->send(); |
22 |
| - |
23 |
| - return null; |
| 19 | + if ($response = $this->handleRateLimiting()) { |
| 20 | + return $response; |
24 | 21 | }
|
25 | 22 |
|
26 | 23 | $data = $this->form->getState();
|
| 24 | + $credentials = $this->getCredentialsFromFormData($data); |
| 25 | + $remember = $data['remember'] ?? false; |
27 | 26 |
|
28 |
| - $responseClass = LoginResponse::class; |
29 |
| - |
30 |
| - if (! Filament::auth()->attempt($this->getCredentialsFromFormData($data), $data['remember'] ?? false)) { |
| 27 | + if (! $this->attemptLogin($credentials, $remember)) { |
31 | 28 | $this->throwFailureValidationException();
|
32 | 29 | }
|
33 | 30 |
|
34 | 31 | $user = Filament::auth()->user();
|
35 | 32 |
|
36 |
| - /** Check If user loggedin with unsafe device redirecting to 2fa verification page */ |
37 |
| - if ($user instanceof TwoFactorAuthenticatable && $user->hasTwoFactorEnabled() && !$user->isSafeDevice(request())) { |
38 |
| - $responseClass = TwoFactorAuthResponse::class; |
39 |
| - $this->flashData($this->getCredentialsFromFormData($data), $data['remember'] ?? false); |
40 |
| - Filament::auth()->logout(); |
41 |
| - goto response; |
| 33 | + if ($response = $this->handleTwoFactorAuthentication($user, $credentials, $remember)) { |
| 34 | + return $response; |
42 | 35 | }
|
43 | 36 |
|
44 |
| - response: |
45 |
| - if ( |
46 |
| - ($user instanceof FilamentUser) && |
47 |
| - (! $user->canAccessPanel(Filament::getCurrentPanel())) |
48 |
| - ) { |
| 37 | + if (! $this->userCanAccessPanel($user)) { |
49 | 38 | Filament::auth()->logout();
|
50 | 39 | $this->throwFailureValidationException();
|
51 | 40 | }
|
52 | 41 |
|
53 | 42 | session()->regenerate();
|
54 | 43 |
|
55 |
| - return app($responseClass); |
| 44 | + return app(LoginResponse::class); |
56 | 45 | }
|
57 | 46 |
|
58 | 47 | /**
|
59 |
| - * Flashes the credentials into the session, encrypted. |
| 48 | + * Handle rate limiting for login attempts. |
60 | 49 | */
|
61 |
| - protected function flashData(array $credentials, bool $remember): void |
| 50 | + protected function handleRateLimiting(): ?LoginResponse |
62 | 51 | {
|
63 |
| - foreach ($credentials as $key => $value) { |
64 |
| - $credentials[$key] = Crypt::encryptString($value); |
| 52 | + try { |
| 53 | + $this->rateLimit(5); |
| 54 | + } catch (TooManyRequestsException $exception) { |
| 55 | + $this->getRateLimitedNotification($exception)?->send(); |
| 56 | + return null; |
65 | 57 | }
|
66 | 58 |
|
| 59 | + return null; |
| 60 | + } |
| 61 | + |
| 62 | + /** |
| 63 | + * Attempt to authenticate the user. |
| 64 | + */ |
| 65 | + protected function attemptLogin(array $credentials, bool $remember): bool |
| 66 | + { |
| 67 | + return Filament::auth()->attempt($credentials, $remember); |
| 68 | + } |
| 69 | + |
| 70 | + /** |
| 71 | + * Handle two-factor authentication if required. |
| 72 | + */ |
| 73 | + protected function handleTwoFactorAuthentication(Authenticatable $user, array $credentials, bool $remember): ?TwoFactorAuthResponse |
| 74 | + { |
| 75 | + if ($this->needsTwoFactorAuthentication($user)) { |
| 76 | + $this->flashCredentials($credentials, $remember); |
| 77 | + Filament::auth()->logout(); |
| 78 | + |
| 79 | + return app(TwoFactorAuthResponse::class); |
| 80 | + } |
| 81 | + |
| 82 | + return null; |
| 83 | + } |
| 84 | + |
| 85 | + /** |
| 86 | + * Determine if two-factor authentication is required. |
| 87 | + */ |
| 88 | + protected function needsTwoFactorAuthentication(Authenticatable $user): bool |
| 89 | + { |
| 90 | + return $user instanceof TwoFactorAuthenticatable |
| 91 | + && $user->hasTwoFactorEnabled() |
| 92 | + && ! $user->isSafeDevice(request()); |
| 93 | + } |
| 94 | + |
| 95 | + /** |
| 96 | + * Check if the authenticated user can access the current panel. |
| 97 | + */ |
| 98 | + protected function userCanAccessPanel(Authenticatable $user): bool |
| 99 | + { |
| 100 | + return ! ($user instanceof FilamentUser && ! $user->canAccessPanel(Filament::getCurrentPanel())); |
| 101 | + } |
| 102 | + |
| 103 | + /** |
| 104 | + * Flash the credentials into the session, encrypted. |
| 105 | + */ |
| 106 | + protected function flashCredentials(array $credentials, bool $remember): void |
| 107 | + { |
| 108 | + $encryptedCredentials = array_map( |
| 109 | + fn($value) => Crypt::encryptString($value), |
| 110 | + $credentials |
| 111 | + ); |
| 112 | + |
| 113 | + $sessionData = [ |
| 114 | + 'credentials' => $encryptedCredentials, |
| 115 | + 'remember' => $remember, |
| 116 | + ]; |
| 117 | + |
| 118 | + $credentialKey = config('filament-2fa.login.credential_key'); |
| 119 | + |
67 | 120 | if (config('filament-2fa.login.flashLoginCredentials')) {
|
68 |
| - request()->session()->flash(config('filament-2fa.login.credential_key'), ['credentials' => $credentials, 'remember' => $remember]); |
| 121 | + request()->session()->flash($credentialKey, $sessionData); |
69 | 122 | } else {
|
70 |
| - session([config('filament-2fa.login.credential_key') => ['credentials' => $credentials, 'remember' => $remember]]); |
| 123 | + session([$credentialKey => $sessionData]); |
71 | 124 | }
|
72 | 125 | }
|
73 | 126 | }
|
0 commit comments