Skip to content
bitzorcas
中EN

Concept

商业分发

负责商业私有包的下载权益与短期 Feed 凭据,并在凭据校验时实时检查权益是否仍有效。

Last updated

负责商业私有包的下载权益与短期 Feed 凭据,并在凭据校验时实时检查权益是否仍有效。

一张图读懂主路径

授予限定范围的权益

签发 1 至 168 小时凭据

Feed 提交 Basic Authentication

解密 Token 并重新查询权益

返回有效范围或统一无效结果

珊瑚色节点表示本模块的核心决策或状态边界。

能力边界

  • 租户、客户、产品、通道与包前缀权益范围
  • 授予与不可逆撤销生命周期
  • 受保护的短期 Feed Token 与失败关闭校验

模块明确不包含:包权益只授予指定产品、版本通道与包前缀的下载范围;它不是运行时许可证或租户 Feature,本模块也不是 NuGet Server 或 Credential Provider。

代码地图

项目主要职责
BitzOrcas.Platform.CommercialDistribution.Contracts公开契约、端口、DTO 与事件
BitzOrcas.Platform.CommercialDistribution.Domain聚合、不变量与纯领域规则
BitzOrcas.Platform.CommercialDistribution.Application命令、查询、处理器与应用策略
BitzOrcas.Platform.CommercialDistribution.Infrastructure持久化、连接器与框架适配器

源码位置: src/Platform/CommercialDistribution

核心用例

  • GrantPackageEntitlementCommand
  • RevokePackageEntitlementCommand
  • ListPackageEntitlementsQuery
  • GetPackageEntitlementQuery
  • IssueFeedTokenCommand
  • ValidateFeedTokenCommand

阅读用例时,先看请求契约和权限声明,再跟进处理器调用的聚合或端口,最后检查提交后的事件、缓存和审计。

关键模型与契约

关键类型阅读重点
PackageEntitlement权益聚合与不变量
PackageEntitlementSummary管理端读模型
IPackageEntitlementCommandStore聚合持久化端口
ICommercialFeedTokenProtector凭据保护扩展缝

用例边界示例

字段说明
代表性契约ValidateFeedTokenCommand
返回结果Result<FeedTokenValidationResult>
审查重点把 introspection 当作失败关闭的网关契约:不暴露失败原因,并在验证 Token 封装后始终重新读取当前权益。

示例伪代码

ValidateFeedTokenCommand 伪代码
// ① 封装或用户名校验失败都返回同一个 inactive 结果。
if (!tokenProtector.TryUnprotect(command.Token, out var payload)
|| payload is null
|| payload.ExpiresAt <= clock.UtcNow
|| command.UserName != $"feed:{payload.CustomerId}")
return FeedTokenValidationResult.Inactive;
// ② 重新查询当前权益,让撤销优先于尚未过期的 Token。
var rights = await entitlements.FindByCustomerAsync(
payload.TenantId, payload.CustomerId, payload.ProductId, cancellationToken);
// ③ Read Store 故障同样关闭访问,且不披露内部原因。
if (rights.IsFailure) return FeedTokenValidationResult.Inactive;
// ④ Active 结果的包前缀与版本通道直接从当前权益行去重、排序后聚合。
return rights.Value.Count == 0
? FeedTokenValidationResult.Inactive
: new FeedTokenValidationResult(true,
payload.CustomerId, payload.ProductId, payload.ExpiresAt,
rights.Value.Select(item => item.PackagePrefix)
.Distinct(StringComparer.Ordinal)
.OrderBy(value => value, StringComparer.Ordinal).ToArray(),
rights.Value.Select(item => item.VersionChannel)
.Distinct(StringComparer.Ordinal)
.OrderBy(value => value, StringComparer.Ordinal).ToArray());

集成关系

Feed 网关在受控网络边界内调用免登录的 introspection 端点。端点先校验受保护载荷,再重新读取有效权益,因此撤销无需等待 Token 自然过期。

本页描述模块内部边界。仓库、Feed 网关、客户侧认证和撤销演练见私有包源与客户认证;包权益与运行时许可证如何分工,见许可证签发。

跨模块协作遵循以下方向:

  • 调用方依赖本模块公开 Contracts 或窄端口。
  • 状态变化通过版本化集成事件传播。
  • 具体数据库、消息、缓存、文件或厂商 SDK 留在 Infrastructure。
  • 组合根先注册失败关闭默认实现,再接入生产适配器。

安全、租户与隐私

管理操作受 commercial-distribution 权限与默认关闭的 feed-management Feature 约束。Token 篡改、过期、用户名不匹配、权益撤销或 Store 故障都返回同一个 inactive 结果,不泄露内部原因。

模块保存租户数据时必须写入 TenantId,列表和详情使用同一授权规则。日志、事件和审计只保留诊断所需字段。

失败语义、幂等与可观测性

同一权益 ID 与范围的重复授予保持幂等,范围变化则冲突;撤销不可逆。列表和详情使用 QueryShape 保持 ORM 中立,Token 的完整性与机密性由 Data Protection 保护。

情况处理原则
校验、未找到、冲突或禁止返回类型化 Result/Error,并由统一映射生成 Problem Details
适配器或关键状态不可用安全或高价值操作失败关闭;只读降级必须显式标记
重复请求或重复事件使用稳定幂等键,数据库唯一约束作为最后防线
外部超时传播取消,记录脱敏诊断,仅对安全操作执行有界重试

测试矩阵

#必须覆盖建议层级
1幂等授予与冲突重放单元 + 集成
2撤销后校验尚未过期的 Token集成/契约
3篡改、过期、用户名不匹配与 Store 故障集成/契约
4Contracts/Application 不直接依赖 EF 或 SqlSugar集成/契约

测试还要固定一条通用红线:租户 A 的标识、缓存键、事件或查询条件不能让租户 B 读取或修改数据。

源码导航与变更检查

在 BitzOrcasVNext 仓库根目录运行:

Terminal window
# 列出公开类型,确认新增契约是否真的属于模块边界。
rg -n "^public (sealed |abstract |static |partial )*(record|class|interface|enum)" src/Platform/CommercialDistribution -g '*.cs'
# 检查跨层引用;调用方不应依赖另一个模块的 Infrastructure。
rg -n "ProjectReference|PackageReference" src/Platform/CommercialDistribution -g '*.csproj'
# 查找待补实现和省略式代码;预期没有命中。
rg -n "TODO|FIXME|// \.\.\.|省略" src/Platform/CommercialDistribution -g '*.cs'

扩展与发布检查

  1. 新能力是否由明确的 Contracts、权限和 Feature Key 表达?
  2. 持久化、连接器和 Provider 是否可以通过窄适配器替换?
  3. 生产组合是否仍命中 Null/Unavailable 默认实现?健康检查会不会误报绿色?
  4. 事务、事件、缓存失效、审计和后台任务是否有失败与重试证据?
  5. 中英文文档、图表、契约测试和运维手册是否随代码一起更新?

返回平台模块目录 · 查看模块依赖图 · 新增模块指南

100%

滚轮或按钮缩放 · 放大后拖动画面 · 双击切换 100% / 200%