forked from xiongyuxing/tiku-backend.net
75 lines
2.9 KiB
C#
75 lines
2.9 KiB
C#
using Microsoft.Extensions.Options;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Tiku.Api.Options;
|
|
using Tiku.Application.Security;
|
|
using Tiku.Application.Tenancy;
|
|
|
|
namespace Tiku.Api.Middleware;
|
|
|
|
public sealed class TenantResolutionMiddleware(RequestDelegate next)
|
|
{
|
|
public async Task InvokeAsync(
|
|
HttpContext context,
|
|
ITenantDirectory tenantDirectory,
|
|
ITenantContextInitializer tenantInitializer,
|
|
IOptions<TenantResolutionOptions> options)
|
|
{
|
|
var host = NormalizeHost(context.Request.Host.Host);
|
|
var isPlatformHost = options.Value.PlatformHosts.Any(candidate =>
|
|
string.Equals(NormalizeHost(candidate), host, StringComparison.OrdinalIgnoreCase));
|
|
|
|
TenantDirectoryEntry? tenant = null;
|
|
if (!isPlatformHost && host is not null)
|
|
{
|
|
tenant = await tenantDirectory.FindByHostAsync(host, context.RequestAborted);
|
|
if (tenant is null && !IsExemptPath(context.Request.Path, options.Value.ExemptPathPrefixes))
|
|
{
|
|
context.Response.StatusCode = StatusCodes.Status404NotFound;
|
|
await context.Response.WriteAsJsonAsync(new ProblemDetails
|
|
{
|
|
Title = "Tenant was not found.",
|
|
Status = StatusCodes.Status404NotFound,
|
|
Detail = "The request host is not assigned to an active tenant."
|
|
}, context.RequestAborted);
|
|
return;
|
|
}
|
|
}
|
|
else if (isPlatformHost && IsAllowedTenantCodePath(
|
|
context.Request.Path,
|
|
options.Value.TenantCodePathPrefixes))
|
|
{
|
|
var tenantCode = context.Request.Headers["x-tenant-code"].FirstOrDefault()
|
|
?? context.Request.Query["tenantCode"].FirstOrDefault();
|
|
if (!string.IsNullOrWhiteSpace(tenantCode))
|
|
{
|
|
tenant = await tenantDirectory.FindByCodeAsync(tenantCode.Trim(), context.RequestAborted);
|
|
}
|
|
}
|
|
|
|
if (tenant is not null)
|
|
{
|
|
tenantInitializer.Initialize(
|
|
tenant.TenantId,
|
|
tenant.TenantCode,
|
|
tenant.Host is null ? TenantResolutionSource.TenantCode : TenantResolutionSource.Host);
|
|
}
|
|
|
|
await next(context);
|
|
}
|
|
|
|
private static string? NormalizeHost(string? host)
|
|
{
|
|
return string.IsNullOrWhiteSpace(host) ? null : host.Trim().TrimEnd('.').ToLowerInvariant();
|
|
}
|
|
|
|
private static bool IsExemptPath(PathString path, IEnumerable<string> prefixes)
|
|
{
|
|
return prefixes.Any(prefix => path.StartsWithSegments(prefix, StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
|
|
private static bool IsAllowedTenantCodePath(PathString path, IEnumerable<string> prefixes)
|
|
{
|
|
return prefixes.Any(prefix => path.StartsWithSegments(prefix, StringComparison.OrdinalIgnoreCase));
|
|
}
|
|
}
|