[ SecurityHeaders::class, EncryptCookies::class, AddQueuedCookiesToResponse::class, StartSession::class, AuthenticateSession::class, ShareErrorsFromSession::class, VerifyCsrfToken::class, SubstituteBindings::class, ModuleSettingsMiddleware::class, Localization::class, HandleInertiaRequests::class, SetDeveloperEnvironment::class, UpdateUserStatus::class, ], 'api' => [ EnsureFrontendRequestsAreStateful::class, 'throttle:api', SubstituteBindings::class, ApiAccessLog::class, ], // Stack für die versionierte Maschinen-API (/api/v1). Bewusst ohne Sanctums // EnsureFrontendRequestsAreStateful — hier authentifiziert ausschließlich ein Bearer-Token, // keine Session. Ebenso ohne throttle:api, weil dessen 60/min pro Benutzer gelten und damit // das feinere Limit pro Token (throttle:api-token) überstimmen würden. 'api.machine' => [ ForceJsonResponse::class, RejectTransientTokens::class, SubstituteBindings::class, ApiAccessLog::class, ], // Stack der App (/api/app/v1): wie api.machine reines Bearer-Token-Auth, aber ohne // ApiAccessLog — das Protokoll gehört zu den Maschinen-Schlüsseln der Schnittstellen-Seite, // Geräte-Tokens tauchen dort nicht auf. 'api.app' => [ RejectTransientTokens::class, SubstituteBindings::class, ], // Isolated stack for external-access (magic-link) users. // Deliberately excludes AuthenticateSession, ModuleSettingsMiddleware, the standard // HandleInertiaRequests (which leaks permissions/roles), SetDeveloperEnvironment, and // UpdateUserStatus — all of those are internal-user concerns. 'external' => [ \Artwork\Modules\ExternalAccess\Http\Middleware\EnsureExternalAccessEnabled::class, SecurityHeaders::class, EncryptCookies::class, AddQueuedCookiesToResponse::class, SwapExternalSessionConfig::class, StartSession::class, ShareErrorsFromSession::class, VerifyCsrfToken::class, SubstituteBindings::class, ExternalAuthenticate::class, CheckExternalAccessValid::class, HandleExternalInertiaRequests::class, Localization::class, ], 'external.guest' => [ \Artwork\Modules\ExternalAccess\Http\Middleware\EnsureExternalAccessEnabled::class, SecurityHeaders::class, EncryptCookies::class, AddQueuedCookiesToResponse::class, SwapExternalSessionConfig::class, StartSession::class, ShareErrorsFromSession::class, VerifyCsrfToken::class, SubstituteBindings::class, RedirectIfAuthenticatedExternal::class, HandleExternalInertiaRequests::class, Localization::class, ], ]; protected $routeMiddleware = [ 'auth' => Authenticate::class, 'auth.basic' => AuthenticateWithBasicAuth::class, 'cache.headers' => SetCacheHeaders::class, 'can' => Authorize::class, 'guest' => RedirectIfAuthenticated::class, 'password.confirm' => RequirePassword::class, 'signed' => ValidateSignature::class, 'throttle' => ThrottleRequests::class, 'verified' => EnsureEmailIsVerified::class, 'role' => RoleMiddleware::class, 'permission' => PermissionMiddleware::class, 'role_or_permission' => RoleOrPermissionMiddleware::class, 'shift-settings-area' => \App\Http\Middleware\EnsureShiftSettingsAreaPermission::class, 'external.scoped' => \Artwork\Modules\ExternalAccess\Http\Middleware\EnsureScopedAccess::class, 'external.crm' => \Artwork\Modules\ExternalAccess\Http\Middleware\EnsureCrmAccessActive::class, ]; /** * Wie der Framework-Kernel, aber Fehler aus den Terminating-Callbacks (dispatch(...)->afterResponse(), * app()->terminating()) werden gemeldet statt geworfen: die Antwort ist bereits gesendet, eine Exception * endete sonst ebenfalls als "headers already sent"-Fatal. Nach einem Fehler entfallen die übrigen * Callbacks dieses Requests. * * @param \Illuminate\Http\Request $request * @param \Symfony\Component\HttpFoundation\Response $response */ public function terminate($request, $response): void { try { parent::terminate($request, $response); } catch (Throwable $throwable) { $this->requestStartedAt = null; report($throwable); } } /** * Wie der Framework-Kernel, aber jede Middleware einzeln abgesichert: terminate() läuft, nachdem die Antwort * gesendet wurde. Eine Exception hier (auch schon beim Neubau der Middleware, z. B. Passports CheckToken, das * den ResourceServer samt OAuth-Key-Prüfung braucht) endete sonst als "headers already sent"-Fatal, verdeckte * die Ursache und übersprang die übrigen terminate()-Aufrufe. Bei Laravel-Upgrades gegen * Illuminate\Foundation\Http\Kernel::terminateMiddleware() abgleichen. * * @param \Illuminate\Http\Request $request * @param \Symfony\Component\HttpFoundation\Response $response */ protected function terminateMiddleware($request, $response): void { $middlewares = $this->app->shouldSkipMiddleware() ? [] : array_merge( $this->gatherRouteMiddleware($request), $this->middleware ); foreach ($middlewares as $middleware) { if (!is_string($middleware)) { continue; } try { [$name] = $this->parseMiddleware($middleware); $instance = $this->app->make($name); if (method_exists($instance, 'terminate')) { $instance->terminate($request, $response); } } catch (Throwable $throwable) { report($throwable); } } } }