认证中心
← 全部文档与搜索
独立页面 ↗下载 Markdown
本文目录 · 6 节

应用奖励兑换码(CDK,原通用码券)

认证中心的应用奖励兑换码服务与用户软件授权激活码相互独立。每个码批次归属于一个应用;接入方使用本应用 API Key 时,不能查询或核销其他应用的码。奖励由接入方根据核销快照完成实际发放,不等于平台软件使用权益。

管理能力

管理后台的「应用奖励兑换码」(旧入口名「通用码券」)支持:

  • 激活码、兑换码、CDK、礼包码、试用码和自定义码;
  • 按批次生成最多 1000 个随机码,加密保存原码并仅以尾号展示;
  • 为批次配置 entitlement_key 和不超过 16 KiB 的 JSON 权益数据,并可保存为按应用隔离的权益模板;
  • 配置开始时间、截止时间、单码总兑换次数、单个主体兑换次数;
  • 在「批次 / 单码 / 核销记录 / 权益模板」四个视角查询和管理;批次可以编辑、整批作废或恢复,单码可以停用或恢复;
  • 未发生核销的批次或单码可永久删除。已有核销记录的对象保留审计历史,只允许作废,避免把已经发生的业务事实抹掉;
  • 记录每次核销的应用、外部主体、幂等键、业务元数据和时间。

修改批次权益只影响修改后的新核销。每次成功核销都会保存当时的权益快照,因此旧请求的幂等重试仍返回原来的权益,不会因管理员后来编辑批次而改变。

当前管理接口仍使用平台范围的 authorizations:write,没有独立的 CDK 只读、写入或原码导出权限。管理页按应用筛选不是授权隔离;上文的应用边界指接入方 API Key 接口。独立权限及历史角色映射由 #23 跟踪,须经明确批准和迁移验收后再实施,不自动扩大既有角色权限。

subject_id 由接入方定义,可以是游戏角色 ID、游戏账号 ID、软件账号 ID 或设备主体。若奖励是账号共享的,应传账号 ID;若奖励属于单角色,应传经过游戏服校验的角色 ID。

应用配置

应用需要启用以下 API Key 权限:

  • codes:read:调用校验接口;
  • codes:redeem:调用原子核销接口。

API Key 只能保存在接入方服务端,不得打包进游戏或软件客户端。两个接口不接受浏览器 Cookie 或 OAuth 用户令牌。

认证中心不会直接修改第三方客户端或游戏账号。客户端只负责收集兑换码并提交给自己的业务服务端;业务服务端核销成功后,必须根据白名单中的 entitlement_key 和经过校验的 payload,在自己的数据库、库存、会员或邮件系统中完成实际发放。

校验接口

POST /api/v1/codes/validate
X-API-Key: <应用 API Key>
Content-Type: application/json

{
  "code": "CDK-...",
  "subject_id": "role-123"
}

HTTP 200 只表示请求成功,必须检查 data.valid。可能的 reason 包括 not_found、disabled、not_started、expired、exhausted 和 subject_limit。校验不会预占或消费兑换次数,不能代替核销。

核销接口

POST /api/v1/codes/redeem
X-API-Key: <应用 API Key>
Content-Type: application/json

{
  "code": "CDK-...",
  "subject_id": "role-123",
  "idempotency_key": "cdk:role-123:request-uuid",
  "metadata": {
    "server_id": "area-1"
  }
}

成功响应示例:

{
  "code": 0,
  "message": "success",
  "data": {
    "redemption_id": "...",
    "duplicate": false,
    "code_type": "cdk",
    "entitlement_key": "starter_pack_v1",
    "payload": {
      "mail_template": "starter",
      "items": [{"id": 1001, "count": 5}]
    },
    "batch_id": "...",
    "batch_name": "新手礼包",
    "starts_at": "...",
    "expires_at": null
  }
}

同一业务请求重试时必须复用相同的 idempotency_key。认证中心会返回原核销结果并将 duplicate 置为 true;同一幂等键若改用其他码或主体,会返回 HTTP 409。

游戏服接入流程

  1. 客户端把 {code, role_id} 发给游戏服的 cdk/redeem RPC。
  2. 游戏服从已认证会话获取用户 ID,并验证 role_id 确实属于该用户。
  3. 游戏服生成并持久化请求 ID,以该值构造稳定的 idempotency_key,调用认证中心核销接口。
  4. 游戏服只按 entitlement_key 查找本地白名单奖励规则;payload 用于经过严格校验的参数,不直接执行任意操作。
  5. 游戏服使用 redemption_id 作为发奖唯一键,在本地事务或发件箱中创建奖励邮件。超时重试认证中心时复用原幂等键,发奖重试时复用原 redemption_id。
  6. 客户端重新拉取账号权益、背包或邮件列表并刷新界面;不要只在客户端本地加数值,因为那既不可信也无法跨设备生效。

这样即使认证中心成功核销后游戏服短暂崩溃,重试也能取得相同结果且不会重复发奖。

数据与安全边界

  • 原码使用 SHA-256 哈希核验,并通过现有 DATA_KEY_FILE 的 AES-GCM 密钥加密保存;日志和核销记录不保存原码。
  • 核销会锁定目标码记录,在一个数据库事务中检查有效期及次数并写入使用记录。
  • 应用 ID 由 API Key 推导,不接受请求体指定,避免跨应用核销。
  • metadata 最大 4 KiB,权益 JSON 最大 16 KiB;管理端批次名称、权益键、备注和次数均有边界校验。
  • 上线前应使用 HTTPS、轮换已泄露的 API Key,并限制认证中心入口仅允许可信游戏服访问。