This commit is contained in:
Thanakarn Klangkasame
2025-09-30 11:01:02 +07:00
commit 92e614674c
182 changed files with 9596 additions and 0 deletions

View File

@@ -0,0 +1,98 @@
using System.Text.RegularExpressions;
using AMREZ.EOP.Abstractions.Applications.Tenancy;
using AMREZ.EOP.Contracts.DTOs.Authentications.Login;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
namespace AMREZ.EOP.Infrastructures.Tenancy;
public sealed class DefaultTenantResolver : ITenantResolver
{
private readonly TenantMap _map;
private readonly ILogger<DefaultTenantResolver>? _log;
// แพลตฟอร์มสลัก (ปรับตามระบบจริงได้) — ใช้ "public" เป็นค่าเริ่ม
private const string PlatformSlug = "public";
public DefaultTenantResolver(
TenantMap map,
ILogger<DefaultTenantResolver>? log = null
)
{
_map = map;
_log = log;
}
public ITenantContext? Resolve(HttpContext http, object? hint = null)
{
var cid = http.TraceIdentifier;
var path = http.Request.Path.Value ?? string.Empty;
// ✅ ทางลัด: ขอ platform ตรง ๆ ด้วย hint
if (hint is string hs && string.Equals(hs, "@platform", StringComparison.OrdinalIgnoreCase))
{
if (_map.TryGetBySlug(PlatformSlug, out var platform))
{
_log?.LogInformation("Resolved by hint=@platform -> {Slug} cid={Cid}", PlatformSlug, cid);
return platform;
}
_log?.LogWarning("Platform slug '{Slug}' not found in TenantMap cid={Cid}", PlatformSlug, cid);
return null;
}
if (path.StartsWith("/api/Tenancy", StringComparison.OrdinalIgnoreCase))
{
if (_map.TryGetBySlug(PlatformSlug, out var platform))
{
// เก็บ target tenant แยกไว้ให้ repo/usecase ใช้
var headerTenant = http.Request.Headers["X-Tenant"].ToString();
if (!string.IsNullOrWhiteSpace(headerTenant))
http.Items["TargetTenantKey"] = headerTenant.Trim().ToLowerInvariant();
_log?.LogInformation("Resolved CONTROL-PLANE -> platform:{Slug} (path={Path}) cid={Cid}", PlatformSlug, path, cid);
return platform;
}
_log?.LogWarning("CONTROL-PLANE path but platform slug '{Slug}' missing cid={Cid}", PlatformSlug, cid);
return null;
}
var header = http.Request.Headers["X-Tenant"].ToString();
if (!string.IsNullOrWhiteSpace(header) && _map.TryGetBySlug(header, out var byHeader))
{
_log?.LogInformation("Resolved by header: {Tenant} cid={Cid}", header, cid);
return byHeader;
}
var host = http.Request.Host.Host;
if (_map.TryGetByDomain(host, out var byDomain))
{
_log?.LogInformation("Resolved by domain: {Host} -> {TenantId} cid={Cid}", host, byDomain.Id, cid);
return byDomain;
}
var sub = GetSubdomain(host);
if (sub != null && _map.TryGetBySlug(sub, out var bySub))
{
_log?.LogInformation("Resolved by subdomain: {Sub} cid={Cid}", sub, cid);
return bySub;
}
if (hint is LoginRequest body && !string.IsNullOrWhiteSpace(body.Tenant) &&
_map.TryGetBySlug(body.Tenant!, out var byBody))
{
_log?.LogInformation("Resolved by body: {Tenant} cid={Cid}", body.Tenant, cid);
return byBody;
}
_log?.LogWarning("Resolve FAILED host={Host} header={Header} cid={Cid}",
host, string.IsNullOrWhiteSpace(header) ? "<empty>" : header, cid);
return null;
}
private static string? GetSubdomain(string host)
{
if (Regex.IsMatch(host, @"^\d{1,3}(\.\d{1,3}){3}$")) return null; // IP
var parts = host.Split('.', StringSplitOptions.RemoveEmptyEntries);
return parts.Length >= 3 ? parts[0] : null;
}
}