feat: enforce tenant isolation and shared question bank

This commit is contained in:
2026-07-27 16:59:12 +08:00
parent 28e9a9fa41
commit db4c7b4496
137 changed files with 6402 additions and 112274 deletions

View File

@@ -7,6 +7,8 @@ using Tiku.Domain.Common;
using Tiku.Domain.Operations;
using Tiku.Domain.Tenancy;
using Tiku.Infrastructure.Persistence;
using Tiku.Application.Security;
using Tiku.Application.Tenancy;
namespace Tiku.Api.Controllers;
@@ -14,7 +16,11 @@ namespace Tiku.Api.Controllers;
[AllowAnonymous]
[Produces("application/json")]
[Route("api/tenant")]
public sealed class TenantPublicController(TikuDbContext dbContext) : ControllerBase
public sealed class TenantPublicController(
TikuDbContext dbContext,
ITenantContext tenantContext,
ITenantContextInitializer tenantContextInitializer,
ITenantDirectory tenantDirectory) : ControllerBase
{
[HttpGet("resolve")]
[EndpointSummary("解析当前租户")]
@@ -28,9 +34,23 @@ public sealed class TenantPublicController(TikuDbContext dbContext) : Controller
var tenantCode = NormalizeTenantCode(query.TenantCode ?? Request.Headers["x-tenant-code"].FirstOrDefault());
var host = NormalizeHost(query.Host ?? Request.Host.Host);
var tenant = !string.IsNullOrWhiteSpace(tenantCode)
? await FindActiveTenantByCodeAsync(tenantCode, cancellationToken)
: await FindActiveTenantByHostAsync(host, cancellationToken);
var directoryEntry = tenantContext.ResolutionSource == TenantResolutionSource.Host
? await tenantDirectory.FindByHostAsync(Request.Host.Host, cancellationToken)
: !string.IsNullOrWhiteSpace(tenantCode)
? await tenantDirectory.FindByCodeAsync(tenantCode, cancellationToken)
: string.IsNullOrWhiteSpace(host)
? null
: await tenantDirectory.FindByHostAsync(host, cancellationToken);
TenantLookupResult? tenant = directoryEntry is null
? null
: new TenantLookupResult(
directoryEntry.TenantId,
directoryEntry.TenantCode,
directoryEntry.Name,
directoryEntry.Status,
directoryEntry.Mode,
directoryEntry.Host);
if (tenant is null)
{
@@ -42,6 +62,11 @@ public sealed class TenantPublicController(TikuDbContext dbContext) : Controller
});
}
tenantContextInitializer.Initialize(
tenant.Id,
tenant.Slug,
tenant.Host is null ? TenantResolutionSource.TenantCode : TenantResolutionSource.Host);
return Ok(await BuildResponseAsync(tenant, tenant.Host, cancellationToken));
}