Redesign
This commit is contained in:
@@ -1,84 +0,0 @@
|
||||
|
||||
/**
|
||||
* Tenant detection and validation middleware for multi-tenant architecture
|
||||
*/
|
||||
import { FastifyRequest, FastifyReply } from 'fastify';
|
||||
import { getTenantConfig, isValidTenant, extractTenantId } from '../config/tenant';
|
||||
import { logger } from '../logging/logger';
|
||||
|
||||
// Extend FastifyRequest to include tenant context
|
||||
declare module 'fastify' {
|
||||
interface FastifyRequest {
|
||||
tenantId: string;
|
||||
tenantConfig: {
|
||||
tenantId: string;
|
||||
databaseUrl: string;
|
||||
redisUrl: string;
|
||||
platformServicesUrl: string;
|
||||
isAdminTenant: boolean;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const tenantMiddleware = async (
|
||||
request: FastifyRequest,
|
||||
reply: FastifyReply
|
||||
) => {
|
||||
try {
|
||||
// Method 1: From environment variable (container-level)
|
||||
const envTenantId = process.env.TENANT_ID;
|
||||
|
||||
// Method 2: From JWT token claims (verify or decode if available)
|
||||
let jwtTenantId = (request as any).user?.['https://motovaultpro.com/tenant_id'] as string | undefined;
|
||||
if (!jwtTenantId && typeof (request as any).jwtDecode === 'function') {
|
||||
try {
|
||||
const decoded = (request as any).jwtDecode();
|
||||
jwtTenantId = decoded?.payload?.['https://motovaultpro.com/tenant_id']
|
||||
|| decoded?.['https://motovaultpro.com/tenant_id'];
|
||||
} catch { /* ignore decode errors */ }
|
||||
}
|
||||
|
||||
// Method 3: From subdomain parsing (if needed)
|
||||
const host = request.headers.host || '';
|
||||
const subdomain = host.split('.')[0];
|
||||
const subdomainTenantId = subdomain !== 'admin' && subdomain !== 'localhost' ? subdomain : undefined;
|
||||
|
||||
// Extract tenant ID with priority: Environment > JWT > Subdomain > Default
|
||||
const tenantId = extractTenantId({
|
||||
envTenantId,
|
||||
jwtTenantId,
|
||||
subdomain: subdomainTenantId
|
||||
});
|
||||
|
||||
// Validate tenant exists
|
||||
const isValid = await isValidTenant(tenantId);
|
||||
if (!isValid) {
|
||||
logger.warn('Invalid tenant access attempt', {
|
||||
tenantId,
|
||||
host,
|
||||
path: request.url,
|
||||
method: request.method
|
||||
});
|
||||
reply.code(403).send({ error: 'Invalid or unauthorized tenant' });
|
||||
return;
|
||||
}
|
||||
|
||||
// Get tenant configuration
|
||||
const tenantConfig = getTenantConfig();
|
||||
|
||||
// Attach tenant context to request
|
||||
request.tenantId = tenantId;
|
||||
request.tenantConfig = tenantConfig;
|
||||
|
||||
logger.info('Tenant context established', {
|
||||
tenantId,
|
||||
isAdmin: tenantConfig.isAdminTenant,
|
||||
path: request.url
|
||||
});
|
||||
|
||||
return;
|
||||
} catch (error) {
|
||||
logger.error('Tenant middleware error', { error });
|
||||
reply.code(500).send({ error: 'Internal server error' });
|
||||
}
|
||||
};
|
||||
Reference in New Issue
Block a user