using Microsoft.AspNetCore.Mvc; namespace Admin.NET.Plugin.AiDOP.Infrastructure; /// /// S0 仓储基础资料的可信租户解析(写/读业务表统一取此值)。 /// /// 铁律(W-01/02/03 修复): /// - 租户只来自认证后的 JWT claim(UserManager.TenantId),前端 payload 的 tenantId 一律忽略; /// - 不使用任何固定默认租户兜底(区别于 QmsTenantScope.Current() 会回落 DefaultTenantId); /// - 无有效租户(无 token → App.User 空 → TenantId=0)→ 拒绝; /// - 超级管理员未显式选择目标租户(其 claim 即自身主租户 )→ 拒绝, /// 必须在登录时选择目标租户(SysAuthService 支持超管登录传 tenantId 覆盖)。 /// public static class AdoS0TenantScope { /// 主/系统租户(超管自身归属,== QmsTenantScope.DefaultTenantId)。仅用作"超管未选租户"的拒绝哨兵,绝不作为业务数据归属。 public const long MainTenantId = 1300000000001L; /// /// 解析当前请求的可信目标租户。成功返回 true 且 tenantId 为非空非 0 的有效租户; /// 失败返回 false 且 error 为明确业务错误(调用方直接 return error)。 /// public static bool TryResolveRequired(out long tenantId, out IActionResult? error) { tenantId = 0; error = null; var um = App.GetRequiredService(); var tid = um.TenantId; // 认证后的 JWT claim;无 token 时为 0 if (tid <= 0) { error = AdoS0ApiErrors.InvalidRequest("无法确定当前租户,请重新登录或选择目标租户"); return false; } // 超管的 claim 若等于自身主租户,视为"未选择目标租户"(不允许自动用超管自身/固定默认租户写业务数据) if (um.SuperAdmin && tid == MainTenantId) { error = AdoS0ApiErrors.InvalidRequest("超级管理员操作前必须选择目标租户"); return false; } tenantId = tid; return true; } }