forked from gongxuegit/tiku-backend.net
feat(security): add distributed authorization foundation
This commit is contained in:
@@ -10,6 +10,7 @@ using Tiku.Domain.Platform;
|
||||
using Tiku.Domain.QuestionBanks;
|
||||
using Tiku.Domain.Tenancy;
|
||||
using Tiku.Infrastructure.Persistence;
|
||||
using Tiku.Infrastructure.Messaging;
|
||||
|
||||
namespace Tiku.Infrastructure.PlatformAdmin;
|
||||
|
||||
@@ -152,6 +153,11 @@ internal sealed class PlatformAdminService(
|
||||
Metadata = JsonObjectOrDefault(command.Metadata)
|
||||
};
|
||||
dbContext.Tenants.Add(tenant);
|
||||
dbContext.TenantAuthPolicies.Add(new TenantAuthPolicy
|
||||
{
|
||||
TenantId = tenant.Id,
|
||||
AllowExternalStudentSelfRegistration = false
|
||||
});
|
||||
AddAudit(dbContext, actor, "platform.tenant.created", tenant.Id, new { tenant.Slug, tenant.Name, tenant.Status, tenant.BillingStatus });
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
return ToTenantItem(tenant, 0, null);
|
||||
@@ -164,7 +170,7 @@ internal sealed class PlatformAdminService(
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await AssertPlatformPermissionAsync(actor, BackendPermissions.PlatformTenantManage, cancellationToken);
|
||||
return await ExecuteSystemAsync("platform tenant status update", async dbContext =>
|
||||
return await ExecuteSystemAsync("platform tenant status update", async (provider, dbContext) =>
|
||||
{
|
||||
var tenant = await dbContext.Tenants
|
||||
.SingleOrDefaultAsync(item => item.Id == command.TenantId && item.Mode != TenantMode.PlatformOwned, cancellationToken)
|
||||
@@ -181,6 +187,13 @@ internal sealed class PlatformAdminService(
|
||||
ToBillingStatus = tenant.BillingStatus,
|
||||
command.Reason
|
||||
});
|
||||
await provider.GetRequiredService<ISecurityEventPublisher>().AuthorizationChangedAsync(
|
||||
tenant.Id,
|
||||
null,
|
||||
"tenant_status_changed",
|
||||
DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
|
||||
$"tenant-status-{tenant.Id:N}",
|
||||
cancellationToken);
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
var domainCount = await dbContext.TenantDomains.CountAsync(domain => domain.TenantId == tenant.Id, cancellationToken);
|
||||
var expiresAt = await dbContext.TenantSubscriptions
|
||||
@@ -255,7 +268,7 @@ internal sealed class PlatformAdminService(
|
||||
CancellationToken cancellationToken = default)
|
||||
{
|
||||
await AssertPlatformPermissionAsync(actor, BackendPermissions.PlatformTenantManage, cancellationToken);
|
||||
return await ExecuteSystemAsync("platform tenant subscription upsert", async dbContext =>
|
||||
return await ExecuteSystemAsync("platform tenant subscription upsert", async (provider, dbContext) =>
|
||||
{
|
||||
await RequireTenantAsync(dbContext, command.TenantId, cancellationToken);
|
||||
if (!await dbContext.PlatformSaasPlans.AnyAsync(plan => plan.Code == NormalizeCode(command.PlanCode), cancellationToken))
|
||||
@@ -285,6 +298,27 @@ internal sealed class PlatformAdminService(
|
||||
subscription.Status,
|
||||
subscription.ExpiresAt
|
||||
});
|
||||
var moduleCodes = await dbContext.PlanModuleEntitlements.AsNoTracking()
|
||||
.Where(item => item.PlanCode == subscription.PlanCode)
|
||||
.Select(item => item.ModuleCode)
|
||||
.Distinct()
|
||||
.ToArrayAsync(cancellationToken);
|
||||
if (moduleCodes.Length == 0)
|
||||
{
|
||||
moduleCodes = ["*"];
|
||||
}
|
||||
var eventPublisher = provider.GetRequiredService<ISecurityEventPublisher>();
|
||||
var version = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
||||
foreach (var moduleCode in moduleCodes)
|
||||
{
|
||||
await eventPublisher.CapabilityChangedAsync(
|
||||
command.TenantId,
|
||||
moduleCode,
|
||||
"subscription_changed",
|
||||
version,
|
||||
$"tenant-subscription-{subscription.Id:N}",
|
||||
cancellationToken);
|
||||
}
|
||||
await dbContext.SaveChangesAsync(cancellationToken);
|
||||
return ToSubscriptionItem(subscription);
|
||||
}, cancellationToken);
|
||||
@@ -719,11 +753,23 @@ internal sealed class PlatformAdminService(
|
||||
string reason,
|
||||
Func<TikuDbContext, Task<TResult>> operation,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return ExecuteSystemAsync(reason, (_, dbContext) => operation(dbContext), cancellationToken);
|
||||
}
|
||||
|
||||
private Task<TResult> ExecuteSystemAsync<TResult>(
|
||||
string reason,
|
||||
Func<IServiceProvider, TikuDbContext, Task<TResult>> operation,
|
||||
CancellationToken cancellationToken)
|
||||
{
|
||||
return tenantExecutionScope.ExecuteAsync(
|
||||
null,
|
||||
reason,
|
||||
async (provider, _) => await operation(provider.GetRequiredService<TikuDbContext>()),
|
||||
new SystemScopeRequest(
|
||||
null,
|
||||
SystemScopeCallerType.Platform,
|
||||
nameof(PlatformAdminService),
|
||||
reason,
|
||||
Guid.NewGuid().ToString("N")),
|
||||
async (provider, _) => await operation(provider, provider.GetRequiredService<TikuDbContext>()),
|
||||
cancellationToken);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user