eaa05d68c1
- Filament v5 multiFactorAuthentication enabled on both panels (App + Email) - HasAppAuthentication + HasEmailAuthentication on User and SuperAdmin - Migration: app_authentication_secret + recovery_codes + email_authentication_at - Sanctum REST API: /api/v1/login, /me, clients, vehicles, work-orders - EnsureTokenMatchesTenant middleware blocks cross-tenant token usage - CsvImportExport service: clients + vehicles bulk via plain CSV - Import/Export buttons on Client + Vehicle list pages - ApiTokens page in tenant panel (generate/revoke + last-used) - BackupAllTenantsCommand + scheduler (daily 03:00, retain 14 days) - Background scheduler in entrypoint.sh
35 lines
990 B
PHP
35 lines
990 B
PHP
<?php
|
|
|
|
namespace App\Http\Middleware;
|
|
|
|
use App\Tenancy\TenantManager;
|
|
use Closure;
|
|
use Illuminate\Http\Request;
|
|
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
|
|
|
|
/**
|
|
* Defense in depth: even though Sanctum auth + TenantScope should isolate
|
|
* tenants, this middleware EXPLICITLY rejects any request where the
|
|
* authenticated user's company_id does not match the resolved tenant.
|
|
*
|
|
* Stops the entire class of "stolen token used on wrong subdomain" attacks.
|
|
*/
|
|
class EnsureTokenMatchesTenant
|
|
{
|
|
public function handle(Request $request, Closure $next)
|
|
{
|
|
$user = $request->user();
|
|
$tenant = app(TenantManager::class)->current();
|
|
|
|
if (! $user || ! $tenant) {
|
|
throw new AccessDeniedHttpException('Tenant context required.');
|
|
}
|
|
|
|
if ($user->company_id !== $tenant->id) {
|
|
throw new AccessDeniedHttpException('Token does not belong to this tenant.');
|
|
}
|
|
|
|
return $next($request);
|
|
}
|
|
}
|