feat: 新增租户管理端 TenantApi 并移除旧 API

This commit is contained in:
root
2026-01-29 11:39:57 +00:00
parent 17dc73c61d
commit 86ef0d6033
60 changed files with 450 additions and 1368 deletions

View File

@@ -26,7 +26,6 @@ using TakeoutSaaS.Shared.Abstractions.Ids;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
using TakeoutSaaS.Infrastructure.App.Persistence.Configurations;
using Microsoft.AspNetCore.Http;
namespace TakeoutSaaS.Infrastructure.App.Persistence;
@@ -37,9 +36,8 @@ public sealed class TakeoutAppDbContext(
DbContextOptions<TakeoutAppDbContext> options,
ITenantProvider tenantProvider,
ICurrentUserAccessor? currentUserAccessor = null,
IIdGenerator? idGenerator = null,
IHttpContextAccessor? httpContextAccessor = null)
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator, httpContextAccessor)
IIdGenerator? idGenerator = null)
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator)
{
/// <summary>
/// 租户聚合根。

View File

@@ -111,16 +111,16 @@ internal abstract class DesignTimeDbContextFactoryBase<TContext> : IDesignTimeDb
return explicitDir;
}
// 1. (空行后) 尝试从当前目录定位解决方案根目录
var currentDir = Directory.GetCurrentDirectory();
var solutionRoot = LocateSolutionRoot(currentDir);
// 2. (空行后) 依次尝试常见 appsettings 目录(仅保留租户管理端 TenantApi
var candidateDirs = new[]
{
currentDir,
solutionRoot,
solutionRoot is null ? null : Path.Combine(solutionRoot, "src", "Api", "TakeoutSaaS.AdminApi"),
solutionRoot is null ? null : Path.Combine(solutionRoot, "src", "Api", "TakeoutSaaS.UserApi"),
solutionRoot is null ? null : Path.Combine(solutionRoot, "src", "Api", "TakeoutSaaS.MiniApi")
solutionRoot is null ? null : Path.Combine(solutionRoot, "src", "Api", "TakeoutSaaS.TenantApi")
}.Where(dir => !string.IsNullOrWhiteSpace(dir));
foreach (var dir in candidateDirs)

View File

@@ -5,7 +5,6 @@ using TakeoutSaaS.Shared.Abstractions.Entities;
using TakeoutSaaS.Shared.Abstractions.Ids;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
using Microsoft.AspNetCore.Http;
namespace TakeoutSaaS.Infrastructure.Common.Persistence;
@@ -16,18 +15,9 @@ public abstract class TenantAwareDbContext(
DbContextOptions options,
ITenantProvider tenantProvider,
ICurrentUserAccessor? currentUserAccessor = null,
IIdGenerator? idGenerator = null,
IHttpContextAccessor? httpContextAccessor = null) : AppDbContext(options, currentUserAccessor, idGenerator)
IIdGenerator? idGenerator = null) : AppDbContext(options, currentUserAccessor, idGenerator)
{
private readonly ITenantProvider _tenantProvider = tenantProvider ?? throw new ArgumentNullException(nameof(tenantProvider));
private readonly IHttpContextAccessor? _httpContextAccessor = httpContextAccessor;
private static readonly string[] PlatformRoleCodes =
{
"super-admin",
"SUPER_ADMIN",
"PlatformAdmin",
"platform-admin"
};
/// <summary>
/// 当前请求租户 ID。
@@ -86,22 +76,8 @@ public abstract class TenantAwareDbContext(
{
if (entry.State == EntityState.Added && entry.Entity.TenantId == 0 && tenantId != 0)
{
if (!IsPlatformAdmin())
{
entry.Entity.TenantId = tenantId;
}
entry.Entity.TenantId = tenantId;
}
}
}
private bool IsPlatformAdmin()
{
var user = _httpContextAccessor?.HttpContext?.User;
if (user?.Identity?.IsAuthenticated != true)
{
return false;
}
return PlatformRoleCodes.Any(user.IsInRole);
}
}

View File

@@ -7,7 +7,6 @@ using TakeoutSaaS.Infrastructure.Common.Persistence;
using TakeoutSaaS.Shared.Abstractions.Ids;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
using Microsoft.AspNetCore.Http;
namespace TakeoutSaaS.Infrastructure.Dictionary.Persistence;
@@ -18,9 +17,8 @@ public sealed class DictionaryDbContext(
DbContextOptions<DictionaryDbContext> options,
ITenantProvider tenantProvider,
ICurrentUserAccessor? currentUserAccessor = null,
IIdGenerator? idGenerator = null,
IHttpContextAccessor? httpContextAccessor = null)
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator, httpContextAccessor)
IIdGenerator? idGenerator = null)
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator)
{
/// <summary>
/// 字典分组集合。

View File

@@ -18,6 +18,24 @@ public sealed class EfIdentityUserRepository(IdentityDbContext dbContext) : IIde
public Task<IdentityUser?> FindByAccountAsync(string account, CancellationToken cancellationToken = default)
=> dbContext.IdentityUsers.AsNoTracking().FirstOrDefaultAsync(x => x.Account == account, cancellationToken);
/// <summary>
/// 根据租户与账号获取后台用户。
/// </summary>
/// <param name="tenantId">租户 ID。</param>
/// <param name="account">账号。</param>
/// <param name="cancellationToken">取消标记。</param>
/// <returns>后台用户或 null。</returns>
public Task<IdentityUser?> FindByAccountAsync(long tenantId, string account, CancellationToken cancellationToken = default)
{
// 1. 标准化账号
var normalized = account.Trim();
// 2. 查询用户(强制租户隔离)
return dbContext.IdentityUsers
.AsNoTracking()
.FirstOrDefaultAsync(x => x.TenantId == tenantId && x.Account == normalized, cancellationToken);
}
/// <summary>
/// 判断账号是否存在。
/// </summary>

View File

@@ -6,7 +6,6 @@ using TakeoutSaaS.Infrastructure.Common.Persistence;
using TakeoutSaaS.Shared.Abstractions.Ids;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
using Microsoft.AspNetCore.Http;
namespace TakeoutSaaS.Infrastructure.Identity.Persistence;
@@ -17,9 +16,8 @@ public sealed class IdentityDbContext(
DbContextOptions<IdentityDbContext> options,
ITenantProvider tenantProvider,
ICurrentUserAccessor? currentUserAccessor = null,
IIdGenerator? idGenerator = null,
IHttpContextAccessor? httpContextAccessor = null)
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator, httpContextAccessor)
IIdGenerator? idGenerator = null)
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator)
{
/// <summary>
/// 管理后台用户集合。

View File

@@ -7,7 +7,6 @@ using TakeoutSaaS.Infrastructure.Common.Persistence;
using TakeoutSaaS.Shared.Abstractions.Ids;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;
using Microsoft.AspNetCore.Http;
namespace TakeoutSaaS.Infrastructure.Logs.Persistence;
@@ -18,9 +17,8 @@ public sealed class TakeoutLogsDbContext(
DbContextOptions<TakeoutLogsDbContext> options,
ITenantProvider tenantProvider,
ICurrentUserAccessor? currentUserAccessor = null,
IIdGenerator? idGenerator = null,
IHttpContextAccessor? httpContextAccessor = null)
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator, httpContextAccessor)
IIdGenerator? idGenerator = null)
: TenantAwareDbContext(options, tenantProvider, currentUserAccessor, idGenerator)
{
/// <summary>
/// 租户审计日志集合。