feat(auth): harden authentication and add configurable two-factor support

This commit is contained in:
2026-07-31 03:12:46 +02:00
parent 235d5f646c
commit e47243f7dc
51 changed files with 2904 additions and 1359 deletions

View File

@@ -0,0 +1,34 @@
<?php
namespace App\Services\Auth;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class SecurityEventRecorder
{
/**
* Record a security event without credentials, tokens, or session IDs.
*
* @param array<string, bool|int|string|null> $context
*/
public function record(
string $event,
?User $user,
Request $request,
array $context = []
): void {
Log::channel(config('auth-ui.security.log_channel'))->notice(
'Authentication security event',
[
'event' => $event,
'user_id' => $user?->getKey(),
'ip_address' => $request->ip(),
'user_agent' => Str::limit((string) $request->userAgent(), 255, ''),
...$context,
]
);
}
}

View File

@@ -8,6 +8,16 @@ use Illuminate\Http\Request;
class TwoFactorChallenge
{
/**
* Determine whether the user must enroll in two-factor authentication.
*/
public function enrollmentRequiredFor(User $user): bool
{
return (bool) config('auth-ui.features.two_factor')
&& (bool) config('auth-ui.features.two_factor_required')
&& ! $user->hasEnabledTwoFactorAuthentication();
}
/**
* Determine whether the user must complete a two-factor challenge.
*/
@@ -25,6 +35,7 @@ class TwoFactorChallenge
$request->session()->put([
'login.id' => $user->getKey(),
'login.remember' => $remember,
'login.started_at' => now()->timestamp,
]);
$request->session()->regenerate();

View File

@@ -0,0 +1,43 @@
<?php
namespace App\Services\Auth;
use App\Models\User;
use Laravel\Fortify\Fortify;
class TwoFactorEnrollmentState
{
/**
* Build the two-factor state shared by setup and profile screens.
*
* @return array{
* available: bool,
* enabled: bool,
* pending: bool,
* requiresPassword: bool,
* qrCodeDataUri: string|null,
* secretKey: string|null
* }
*/
public function for(User $user): array
{
$available = (bool) config('auth-ui.features.two_factor');
$enabled = $available && $user->hasEnabledTwoFactorAuthentication();
$pending = $available
&& filled($user->two_factor_secret)
&& ! $enabled;
return [
'available' => $available,
'enabled' => $enabled,
'pending' => $pending,
'requiresPassword' => $user->hasPassword(),
'qrCodeDataUri' => $pending
? 'data:image/svg+xml;base64,'.base64_encode($user->twoFactorQrCodeSvg())
: null,
'secretKey' => $pending
? Fortify::currentEncrypter()->decrypt($user->two_factor_secret)
: null,
];
}
}