17dca0dfad
Die vorige Aufgabe-2-Teilcommit (11f5731) hatte nur die Loeschung von
tenant.middleware.ts und die neue tenant.guard.spec.ts erfasst — ein
`git add` mit mehreren Pfaden schlug wegen eines bereits entfernten
Pfads fataler fehl und liess die restlichen fuenf Dateien unstaged,
ohne dass das beim Commit auffiel (Rule 1 — Prozessfehler, hier
korrigiert). Dieser Commit traegt den eigentlichen Umbau nach:
tenant.guard.ts ohne Prisma-Abhaengigkeit, die geleerte
FORTENANT_ASSIGNMENT_EXCEPTIONS samt Wachhund-Test in
rls-access-inventory.spec.ts, und die drei berichtigten
Kommentarzeilen (app.module.ts, module.guard.ts, dkv.controller.ts).
Inhaltlich identisch mit dem, was bereits verifiziert wurde (891 Tests
gruen, Typpruefung sauber) — nur die Staging-Reihenfolge war fehlerhaft.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AMASaSxv5QMY7RncqZriRR
61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
import {
|
|
CanActivate,
|
|
ExecutionContext,
|
|
ForbiddenException,
|
|
Injectable,
|
|
} from '@nestjs/common';
|
|
|
|
/**
|
|
* Runs AFTER JwtAuthGuard (guard execution order follows APP_GUARD registration order).
|
|
* At this point req.user is populated — the order is load-bearing.
|
|
*
|
|
* Sets ONLY req.tenantId for downstream code. Super-Admin can override the
|
|
* tenant via the x-tenant-id header (D-10).
|
|
*
|
|
* DECISION (260911-e2s, Aufgabe 2): an earlier design also published a
|
|
* tenant-scoped Prisma client on the request object, under a property
|
|
* named `tenantPrisma` (assigned via `forTenant(...)`), duplicated
|
|
* identically in a never-registered Express middleware class with the same
|
|
* logic (deleted with 260911-e2s). A full-text search across
|
|
* `apps/api/src` found no reader of that property outside those two
|
|
* files — every one of the nine areas converted before this one binds
|
|
* service-internally instead, one client per method call via the
|
|
* tenant-binding helper in
|
|
* `prisma-tenant.extension.ts`. That convention, settled by nine-fold
|
|
* practice, is why this guard no longer creates a client at all: dead
|
|
* wiring that LOOKS like a protection mechanism is worse than none — it
|
|
* suggests a safeguard to a later reader that never actually ran. See
|
|
* docs/mandantentrennung-etappe2-fehlerrichtung.md, section "## Bereich
|
|
* tenant", (n4)(a) for the measurement and the reasoning.
|
|
*/
|
|
@Injectable()
|
|
export class TenantGuard implements CanActivate {
|
|
canActivate(context: ExecutionContext): boolean {
|
|
const req = context.switchToHttp().getRequest();
|
|
const user = req.user;
|
|
|
|
if (!user) {
|
|
// Public route (login, health) — skip tenant context
|
|
return true;
|
|
}
|
|
|
|
let tenantId: string | undefined = user.tenantId;
|
|
|
|
if (user.role === 'SUPER_ADMIN' && req.headers['x-tenant-id']) {
|
|
tenantId = req.headers['x-tenant-id'] as string;
|
|
}
|
|
|
|
if (!tenantId && user.role !== 'SUPER_ADMIN') {
|
|
throw new ForbiddenException('No tenant context');
|
|
}
|
|
|
|
if (tenantId) {
|
|
req.tenantId = tenantId;
|
|
} else {
|
|
req.tenantId = null;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|