RoleAwareLoginResponse gab bei wantsJson() sofort 204 zurück – VOR den Sicherheitschecks. Ein XHR/JSON-Login eines verifiziert-inaktiven Accounts erhielt damit eine Session ohne Logout. Checks laufen jetzt zuerst: verifiziert-inaktiv → Logout + Session-Invalidate + 403 (JSON) bzw. Login mit Fehler (HTML); unverifiziert → 204 (JSON) bzw. Notice (HTML); danach der Erfolgsfall. Tests: JSON-Login eines inaktiven Accounts (403, guest), JSON-Login eines aktiven Users (204, authentifiziert). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
61 lines
2.5 KiB
PHP
61 lines
2.5 KiB
PHP
<?php
|
||
|
||
namespace App\Http\Responses;
|
||
|
||
use App\Support\LoginRedirect;
|
||
use Illuminate\Http\JsonResponse;
|
||
use Illuminate\Http\RedirectResponse;
|
||
use Illuminate\Http\Request;
|
||
use Illuminate\Support\Facades\Auth;
|
||
use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;
|
||
use Laravel\Fortify\Contracts\TwoFactorLoginResponse as TwoFactorLoginResponseContract;
|
||
|
||
/**
|
||
* Einheitliche Antwort für den Fortify-POST-Login (HTML und JSON/XHR) UND den
|
||
* Abschluss der 2FA-Challenge. Spiegelt dieselbe Policy wie der Volt-Login:
|
||
* - verifiziert, aber inaktiv → Session beenden, KEIN Login (auch für JSON)
|
||
* - unverifiziert → Verifizierungs-Notice (JSON: 204, verified-Middleware schützt)
|
||
* - sonst rollengerechter, 403-sicherer Redirect (intended nur wenn erreichbar)
|
||
*
|
||
* Wichtig: Die Sicherheitsprüfungen laufen VOR dem JSON-Kurzschluss, damit ein
|
||
* XHR-Login keine Session für einen deaktivierten Account erhält.
|
||
*/
|
||
class RoleAwareLoginResponse implements LoginResponseContract, TwoFactorLoginResponseContract
|
||
{
|
||
public function toResponse($request): RedirectResponse|JsonResponse
|
||
{
|
||
$user = $request->user();
|
||
$wantsJson = $request instanceof Request && $request->wantsJson();
|
||
|
||
// Sicherheits-Boundary zuerst: ein verifizierter, aber deaktivierter
|
||
// Account darf keine Session behalten – egal ob HTML oder JSON.
|
||
if ($user && $user->hasVerifiedEmail() && ! $user->is_active) {
|
||
Auth::guard('web')->logout();
|
||
$request->session()->invalidate();
|
||
$request->session()->regenerateToken();
|
||
|
||
$message = __('Ihr Konto ist nicht aktiv. Bitte wenden Sie sich an den Support.');
|
||
|
||
return $wantsJson
|
||
? new JsonResponse(['message' => $message], 403)
|
||
: redirect()->route('login')->withErrors(['email' => $message]);
|
||
}
|
||
|
||
// Unverifizierte Selbst-Registrierer sind authentifiziert, aber die
|
||
// verified-Middleware sperrt geschützte Routen. HTML → Notice, JSON → 204.
|
||
if ($user && ! $user->hasVerifiedEmail()) {
|
||
return $wantsJson
|
||
? new JsonResponse('', 204)
|
||
: redirect()->route('verification.notice');
|
||
}
|
||
|
||
if ($wantsJson) {
|
||
return new JsonResponse('', 204);
|
||
}
|
||
|
||
$default = LoginRedirect::homeFor($user);
|
||
$intended = $request->session()->pull('url.intended');
|
||
|
||
return redirect(LoginRedirect::safeTarget($user, $intended, $default));
|
||
}
|
||
}
|