| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071 |
- using Admin.NET.Core;
- namespace Admin.NET.Plugin.AiDOP.Infrastructure;
- /// <summary>
- /// S8 可信作用域:租户与工厂一律由服务端从认证身份解析,客户端传入的
- /// tenantId / factoryId / body.TenantId / body.FactoryId 不承担任何安全边界作用。
- /// </summary>
- public sealed record S8TrustedScope(long TenantId, long FactoryId);
- /// <summary>
- /// S8 租户 / 工厂可信作用域解析器(S8-TENANT-FACTORY-P0-CLOSURE-1)。
- ///
- /// 租户:只信认证后的 JWT,复用 <see cref="AidopTenantScope.ResolveOrThrow"/>。
- ///
- /// 工厂:沿用 S8 订单链路(S8OrderFlowService)已在生产路径上实际工作的口径——
- /// 在当前可信租户范围内解析业务工厂组织,而不是取租户根组织 <c>SysTenant.OrgId</c>:
- /// 1. 当前登录用户的组织,且该组织确实属于当前可信租户 → 直接采用;
- /// 2. 否则在当前租户内查 <see cref="FactoryOrgType"/> 工厂类型组织:
- /// 有且仅有 1 个 → 采用;0 个 → 明确业务错误;多于 1 个 → 明确要求消歧,不做任意 First()。
- ///
- /// 不做以下回落(会把归属判错或悄悄放大可见范围):
- /// 租户根组织 / <c>SysTenant.OrgId</c> / 常量 1 / 客户端传入值。
- /// </summary>
- public sealed class S8TrustedScopeResolver : ITransient
- {
- /// <summary>SysOrg.Type 中代表「工厂」的机构类型编码。</summary>
- public const string FactoryOrgType = "501";
- private readonly SqlSugarRepository<SysOrg> _orgRep;
- private readonly UserManager _userManager;
- public S8TrustedScopeResolver(SqlSugarRepository<SysOrg> orgRep, UserManager userManager)
- {
- _orgRep = orgRep;
- _userManager = userManager;
- }
- /// <summary>解析当前登录身份的 S8 可信作用域;无法确定时抛业务异常,绝不回落默认值。</summary>
- public async Task<S8TrustedScope> ResolveAsync()
- {
- var tenantId = AidopTenantScope.ResolveOrThrow(_userManager);
- var factoryId = await ResolveFactoryIdAsync(tenantId);
- return new S8TrustedScope(tenantId, factoryId);
- }
- private async Task<long> ResolveFactoryIdAsync(long tenantId)
- {
- // 1) 登录用户自身组织:必须确实隶属当前可信租户,避免跨租户组织被当作工厂。
- var orgId = _userManager.OrgId;
- if (orgId > 0)
- {
- var belongsToTenant = await _orgRep.AsQueryable()
- .Where(o => o.Id == orgId && o.TenantId == tenantId)
- .AnyAsync();
- if (belongsToTenant) return orgId;
- }
- // 2) 租户内工厂类型组织;必须唯一,否则要求显式消歧。
- var factories = await _orgRep.AsQueryable()
- .Where(o => o.TenantId == tenantId && o.Type == FactoryOrgType)
- .Select(o => o.Id)
- .ToListAsync();
- // 文案面向使用者:说清是什么状态、该找谁、去哪里配,不暴露表名 / 列名。
- if (factories.Count == 1) return factories[0];
- if (factories.Count == 0)
- throw Oops.Oh("当前账号尚未归属有效工厂,请联系管理员在「机构管理」中为该租户配置工厂并绑定用户所属机构");
- throw Oops.Oh("当前租户存在多个工厂,无法确定本次操作的工厂,请联系管理员为该账号绑定唯一所属工厂");
- }
- }
|