Add two factor (#632)

This commit is contained in:
Saeed Vaziry
2025-06-27 01:07:33 +02:00
committed by GitHub
parent 73c836bfe7
commit 194143d7ef
12 changed files with 388 additions and 49 deletions

View File

@ -49,6 +49,18 @@ public function store(Request $request): RedirectResponse
RateLimiter::clear($this->throttleKey());
Session::regenerate();
if (user()->two_factor_secret) {
$request->session()->invalidate();
$request->session()->regenerateToken();
$request->session()->put([
'login.id' => user()->id,
'login.remember' => $request->boolean('remember'),
]);
return redirect()->route('two-factor.login');
}
return redirect()->intended(route('servers', absolute: false));
}

View File

@ -0,0 +1,63 @@
<?php
namespace App\Http\Controllers\Auth;
use App\Models\User;
use Illuminate\Contracts\Auth\StatefulGuard;
use Illuminate\Http\Exceptions\HttpResponseException;
use Illuminate\Routing\Controller;
use Inertia\Inertia;
use Laravel\Fortify\Contracts\FailedTwoFactorLoginResponse;
use Laravel\Fortify\Contracts\TwoFactorLoginResponse;
use Laravel\Fortify\Events\RecoveryCodeReplaced;
use Laravel\Fortify\Events\TwoFactorAuthenticationFailed;
use Laravel\Fortify\Events\ValidTwoFactorAuthenticationCodeProvided;
use Laravel\Fortify\Http\Requests\TwoFactorLoginRequest;
use Spatie\RouteAttributes\Attributes\Get;
use Spatie\RouteAttributes\Attributes\Post;
use Symfony\Component\HttpFoundation\Response;
class TwoFactorAuthenticatedSessionController extends Controller
{
protected StatefulGuard $guard;
public function __construct(StatefulGuard $guard)
{
$this->guard = $guard;
}
#[Get('two-factor', name: 'two-factor.login')]
public function create(TwoFactorLoginRequest $request): \Inertia\Response
{
if (! $request->hasChallengedUser()) {
throw new HttpResponseException(redirect()->route('login'));
}
return Inertia::render('auth/two-factor');
}
#[Post('two-factor', name: 'two-factor.store')]
public function store(TwoFactorLoginRequest $request): TwoFactorLoginResponse|Response
{
/** @var User $user */
$user = $request->challengedUser();
if ($code = $request->validRecoveryCode()) {
$user->replaceRecoveryCode($code);
event(new RecoveryCodeReplaced($user, $code));
} elseif (! $request->hasValidCode()) {
event(new TwoFactorAuthenticationFailed($user));
return app(FailedTwoFactorLoginResponse::class)->toResponse($request);
}
event(new ValidTwoFactorAuthenticationCodeProvided($user));
$this->guard->login($user, $request->remember());
$request->session()->regenerate();
return redirect()->intended(route('servers', absolute: false));
}
}

View File

@ -11,9 +11,12 @@
use Illuminate\Validation\Rules\Password;
use Inertia\Inertia;
use Inertia\Response;
use Laravel\Fortify\Actions\DisableTwoFactorAuthentication;
use Laravel\Fortify\Actions\EnableTwoFactorAuthentication;
use Spatie\RouteAttributes\Attributes\Get;
use Spatie\RouteAttributes\Attributes\Middleware;
use Spatie\RouteAttributes\Attributes\Patch;
use Spatie\RouteAttributes\Attributes\Post;
use Spatie\RouteAttributes\Attributes\Prefix;
use Spatie\RouteAttributes\Attributes\Put;
@ -65,4 +68,30 @@ public function password(Request $request): RedirectResponse
return to_route('profile');
}
#[Post('/enable-two-factor', name: 'profile.enable-two-factor')]
public function enableTwoFactor(): RedirectResponse
{
$user = user();
app(EnableTwoFactorAuthentication::class)($user);
return back()
->with('success', 'Two factor authentication enabled.')
->with('data', [
'qr_code' => $user->twoFactorQrCodeSvg(),
'qr_code_url' => $user->twoFactorQrCodeUrl(),
'recovery_codes' => $user->recoveryCodes(),
]);
}
#[Post('/disable-two-factor', name: 'profile.disable-two-factor')]
public function disableTwoFactor(): RedirectResponse
{
$user = user();
app(DisableTwoFactorAuthentication::class)($user);
return back()->with('success', 'Two factor authentication disabled.');
}
}