Skip to content

多租户与用量模式篇

目标:让集成方读懂 ATKONBASE 的多租户隔离模型,用 /v1/tenants/me/storage 获取当前租户的存储用量与配额,按租户维度聚合二次计费,并理解 TRUSTED_DELEGATED 跨租户场景下用量归属语义。

不在本篇范围:TRUSTED_DELEGATED 身份请求头的完整用法与 granteeId 解析(见 认证与身份双通道模式篇);容器级用量统计(见 容器模型与层级模式篇 §三 containers/stats);配额超限错误码(173008 TENANT_QUOTA_EXCEEDED,触发于预签名直传与内容摄入,见文件上传链路模式篇);错误码完整码表(见错误码参考)。

本篇是集成拓扑 §TRUSTED_DELEGATED 的用量维度纵深,以及领域模型 中租户硬隔离机制的集成方视角说明。

多租户隔离(用前必读)

ATKONBASE 采用多租户硬隔离:所有内容资源(容器 / 文档 / 版本 / ACL / 字段值 / 分享等)均在租户作用域内,不同租户之间的数据相互隔离,任何 V1 API 调用都无法越界读写其他租户数据

  • 每个 API Client(clientId)归属一个租户;token 中的 tenantIdclientId 在服务端解码,不可被集成方伪造或篡改。
  • 租户过滤自动注入:V1 所有资源端点在查询层自动注入当前租户过滤,集成方无需也不应手动在请求里传 tenantId 做隔离。

TRUSTED_DELEGATED 跨租户场景

在多租户 ISV 嵌入部署中,一个 ISV 应用可能为多个下游客户(每个客户是一个租户)各自持有独立凭据。此时:

  • 集成方为每个租户持有对应 clientId / clientSecret,分别换 token 调用。
  • 用量归属/v1/tenants/me/storage 返回的是当前 token 所归属租户的用量;ISV 做聚合二次计费时,按租户分别调用、按 tenantId 对应自己客户汇总,不要用同一 token 调用后手动拆分。
  • 弱通道(X-Atk-Act-As-Source + X-Atk-Act-As-Source-Id)在跨租户场景下:被委派的外部用户必须归属当前 token 所在租户,平台会校验跨租户合法性——非当前租户的用户主张会被拒绝(HTTP 403)。

更多隔离模式细节见集成拓扑 §多租户隔离;委派头的完整规约见 认证与身份双通道模式篇

关键事实

  • 端点:GET /v1/tenants/me/storage,所需 scope:client:storage:tenant:read
  • 返回值含 5 分钟级缓存延迟sampledAt 字段为采样时刻 epoch 毫秒——不应视为实时强一致数据。
  • 可选参数 dimension=physical:切换到物理用量(去重后实际占用字节);默认或传其他任何值均返回逻辑用量(不报错)。
  • quotaBytes=null 表示该租户未设置存储配额上限(无限制);集成方做 UI 时需处理此 null 情形(不要直接做除法计算百分比)。

curl 示例

bash
# 逻辑用量(默认)
curl -X GET 'https://api.atkonbase.example.com/v1/tenants/me/storage' \
  -H 'Authorization: Bearer ${accessToken}'

# 物理用量
curl -X GET 'https://api.atkonbase.example.com/v1/tenants/me/storage?dimension=physical' \
  -H 'Authorization: Bearer ${accessToken}'

期望响应(关键字段)

json
{
  "code": 0,
  "data": {
    "tenantId": "T1000001",
    "dimension": "logical",
    "usageBytes": 104857600,
    "logicalUsageBytes": 104857600,
    "physicalUsageBytes": 89478485,
    "documentCount": 320,
    "versionCount": 540,
    "quotaBytes": 10737418240,
    "softLimitRatio": 0.8,
    "enforced": false,
    "sampledAt": 1748426400000
  }
}
字段含义
tenantId当前租户 ID
dimension本次返回的用量维度:logical(逻辑)/ physical(物理)
usageBytesdimension 给出的对应口径用量(集成方展示给用户时用此字段)
logicalUsageBytes逻辑用量 = 所有文档版本大小求和(含历史版本,不去重)——用户感知值
physicalUsageBytes物理用量 = 对象存储中去重后实际占用字节——对象存储实际计费参考
documentCount租户内文档总数(ACTIVE + ARCHIVED,不含 TRASHED)
versionCount租户内版本总数
quotaBytes配额上限(字节);null 表示无限制
softLimitRatio软限阈值(0 ~ 1);usageBytes / quotaBytes ≥ softLimitRatio 时集成方可提示用户
enforced是否启用 hard-block(达配额时拒绝新写入);当前版本通常为 false
sampledAt采样时刻 epoch 毫秒(5 分钟级缓存,不反映实时用量)

ISV 二次计费要点

ATKONBASE 按租户硬隔离用量,ISV 嵌入模式下集成方可:

  1. 为每个下游客户开一个租户(对应一套 clientId / clientSecret)。
  2. 定期(如每小时 / 每日)用对应租户 token 调 /v1/tenants/me/storage,拿 usageBytes 按自己的计费模型折算。
  3. tenantId 与自己客户 ID 的映射表汇总,对客户做二次计费账单。

⚠️ logicalUsageBytesphysicalUsageBytes 在有大量重复文件(相同内容多次上传)的租户中可能差距显著:逻辑量按每个版本独立计,物理量按去重后实际对象计。两者均正确——选哪个维度做计费基准应与商务条款一致。

常见坑

  • ⚠️ sampledAt 表示当前时间sampledAt 是采样时刻(可能滞后最多 5 分钟),不是请求时刻;高频轮询也不会提高实时性,用量数字不随每次请求重新计算。
  • ⚠️ quotaBytes=null 做除法计百分比:null 表示无限制;直接计算会 NaN / 空指针,集成方需先判 null 再做比例换算。
  • ⚠️ 容器 totalSizeBytes 累加代替租户用量:容器 stats.totalSizeBytes 是该容器子树的逻辑量;用多个容器累加与 /tenants/me/storage 结果不等(范围不同、时效不同、口径可能不同)。租户级存储计费应读本端点,不要用容器级累加。
  • ⚠️ 跨租户共用一个 token:ISV 的不同下游客户是不同租户,必须各自持对应凭据换 token,共用一个 token 会让所有写操作归属到同一租户,且用量无法按客户区分。

不在本段范围

下一步