- R-01: ApiNewsroomAssignment hängt an eine bestehende Firma nur noch Owner, Mitglieder oder Nutzer aus NEWSROOM_API_ASSIGNMENT_USER_IDS; Pivot mit granted_via = api; Befehl company-memberships:api-assignments (Liste, --remove mit Vorschau) - K-04: OAuth-Verifikation eines offenen Kontos verwirft Passwort, remember_token und Sanctum-Tokens; SessionRevocation + Middleware EnsureSessionIsNotRevoked widerruft alte Sessions (Redis-tauglich) - K-08: LoginCompletion für Passwort, Magic Link und Google — last_login_at und Anmeldemethode auch nach 2FA, Landeziel über die Challenge, Google ohne erzwungenes remember, magic-login ohne guest für eigene Links - B-10: eigener Magic-Link-Zweck image_confirmation (Migration) - K-07: legalAcceptanceVersions #[Locked], Versionswechsel beim Absenden wird abgelehnt, Gate-Abfragen je Request zwischengespeichert Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
52 lines
1.5 KiB
PHP
52 lines
1.5 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Middleware;
|
|
|
|
use App\Services\Auth\SessionRevocation;
|
|
use Closure;
|
|
use Illuminate\Auth\SessionGuard;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Support\Facades\Auth;
|
|
use Symfony\Component\HttpFoundation\Response;
|
|
|
|
/**
|
|
* Meldet eine Session ab, die vor der letzten Sperre ihres Kontos entstanden
|
|
* ist (SessionRevocation, Audit K-04). Kostet je angemeldetem Request einen
|
|
* Cache-Zugriff; Gäste lösen keinen aus.
|
|
*/
|
|
class EnsureSessionIsNotRevoked
|
|
{
|
|
public function __construct(private readonly SessionRevocation $revocation) {}
|
|
|
|
public function handle(Request $request, Closure $next): Response
|
|
{
|
|
if (! $request->hasSession()) {
|
|
return $next($request);
|
|
}
|
|
|
|
/** @var SessionGuard $guard */
|
|
$guard = Auth::guard('web');
|
|
|
|
if (! $guard->hasUser() && ! $request->session()->has($guard->getName())) {
|
|
return $next($request);
|
|
}
|
|
|
|
$user = $guard->user();
|
|
|
|
if ($user === null || ! $this->revocation->isRevoked((int) $user->getAuthIdentifier(), $request->session())) {
|
|
return $next($request);
|
|
}
|
|
|
|
// Ohne logout(): das würde remember_token erneut rotieren und damit
|
|
// auch die gerade gültige Anmeldung des Kontoinhabers treffen.
|
|
$guard->logoutCurrentDevice();
|
|
$request->session()->invalidate();
|
|
$request->session()->regenerateToken();
|
|
|
|
if ($request->expectsJson()) {
|
|
abort(401);
|
|
}
|
|
|
|
return redirect()->guest(route('login'));
|
|
}
|
|
}
|