RP 子系统¶
同一个 RP 下可拥有多个子系统。RP 仅由管理员注册;子系统则基于对 RP 的信任自动注册 (find-or-create)。在手机的授权确认界面上,子系统名称以大号字显示, 其下方以小号字显示父级 RP 的名称。
协议(核心思路)¶
RP 调用中并未新增字段 —— 请求体中的 relyingPartyName 被复用为子系统名称。
对已注册的 RP 而言,该字段此前会被 rp.Name 覆盖而失去意义(用于防止冒名)。现在:
服务端(newSession、store.go):
1. 根据密钥(Bearer)确定 RP(CreatorRP)—— 不信任请求体中的 UUID。
2. 通过 resolveSubsystem(find-or-create)将 relyingPartyName 解析为该 RP 下的子系统。
键为 lower(trim(name))(name_key),在同一 RP 内唯一。
3. 会话中:RPName = rp.Name(权威值,小号字)、SubsystemName(大号字)、SubsystemID。
若 relyingPartyName 为空,或与 RP 名称相同 → 使用默认子系统(名称与 RP 相同)。
遗留 RP(例如网页演示中的 “Demo Bank”)会发送自身名称,因此会直接映射到默认子系统 ——
保持向后兼容。
first-party(运营方)与 dev("")调用方没有子系统(RP 未注册)——
SubsystemName 为空,手机上仅单独显示 RPName。
注册与防护¶
- 注册 RP 时,总会创建一个与其同名的默认子系统(
Register)。 - 上限:每个 RP 最多可拥有
SMARTID_RP_SUBSYSTEM_MAX(默认 50)个子系统。 超出后新的自动创建会被拒绝(ErrSubsystemCap→ HTTP 429)。已有子系统继续正常工作。 - 管理员只能编辑子系统:重命名 / 合并 / 停用。不支持手动创建(由 RP 自动创建)。
计数器¶
每当会话成功(OK)结束时,子系统记录上的 auth_count / sign_count / last_used_at
会被原子递增(recordSessionActivity、crypto_wired.go)。RP 的总计 = 其各子系统之和。
管理控制台在 RP 列表中显示“子系统(活跃 / 总数)”以及各子系统的计数。
接口(管理员,/v3/admin/*)¶
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | relying-parties/{id}/subsystems |
RP 的子系统 + 计数(rp:read) |
| PATCH | relying-parties/{id}/subsystems/{sid} |
重命名(rp:write) |
| POST | relying-parties/{id}/subsystems/{sid}/deactivate | /activate |
启用状态 |
| POST | relying-parties/{id}/subsystems/{sid}/merge {targetId} |
将 src 的计数合并至 dst |
相关文件¶
- 数据库:
server/migrations/V30__rp_subsystems.sql(并为遗留 RP 回填默认子系统)。 - 模型 / 仓储:
persistence/models.go(Subsystem,会话上的SubsystemID/Name)、repo/repo.go(Subsystems)、repo/inmem、repo/pg、postgres/subsystem_repo.go。 - 逻辑:
service/memory/store.go(resolveSubsystem、管理操作)、crypto_wired.go(计数)。 - 手机端:iOS
SessionInfo.subsystemName+ContentView/RequestView;AndroidSessionInfo+RequestView.kt—— 子系统用大号字,RP 在下方用小号字(名称相同时只显示 RP)。 - 管理端:
admin/src/app/(app)/rps/page.tsx(子系统展开与管理)、page.tsx(控制台)。
安全说明¶
子系统名称是由 RP 提供的自由文本(RP 理论上可以填写 “Google” 之类的名称)。防护措施: (a) 子系统被限定在其所属 RP 范围内;(b) 权威的 RP 名称始终以小号字显示在下方; (c) 数量上限 + 管理员的合并 / 重命名 / 停用能力。这与“信任 RP”的模型保持一致。
推送通知以子系统名称为主要显示项(<子系统>(<RP>)—— 当名称与 RP 不同时);
若为空则显示 RP。apns.go 的正文与 payload 中包含 subsystemName。
用户打开手机后,授权界面依据 sessionInfo 以大号字确认子系统,并在下方以小号字显示 RP。