Files
story/docs/首次配网设备认证与绑定_SaaS支撑功能分析.md
T
2026-09-12 08:57:29 +08:00

279 lines
28 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 首次配网设备认证与绑定 SaaS 支撑功能分析
分析日期:2026 年 9 月 11 日
依据:附件《AI电话 首次配网 注册与激活 完整流程与详细设计》,整合日期 2026 年 9 月 8 日,公共契约 ONBOARDING-1.1;以及当前工作区 SaaS 的路由、服务、数据库迁移和前端代码。
结论:现有平台具备设备建档、独立密钥、设备鉴权、家庭和使用者权限、绑定关系、设备配置与命令、供应商凭据和审计等基础,但尚未实现附件要求的完整首次接入流程。主要新增工作是可信首次校时、设备注册协议、云端设置会话、手机入口交接、登录后按键确认绑定,以及绑定状态保存回执。激活任务也需要独立的持久化状态和异常恢复机制。
本分析只列 SaaS 要承担的工作及其设备协议边界。Wi-Fi 扫描、密码保存、AP、NAPT、GPIO 和设备存储的具体实现由设备承担。SaaS 不接收家庭 Wi-Fi 密码。本文区分附件要求、当前实现和实施建议;附件中的设计不代表这些功能已经上线。
核对方式:读取正文、附件 A 至 K 和 5 张流程图;静态检查实际路由和实现。附件列出的 18 个云端接口均未在当前 router 中以相同方法和路径注册,但部分能力有现有服务可复用。附件 H 的 HMAC 示例和三组热点名称向量已离线复算一致。没有进行真实设备、短信服务或供应商联调。
## 1 SaaS 应负责的完整业务顺序
1. 受控生产流程登记设备身份和密钥,建立唯一库存记录。
2. 设备联网后请求可信时间,再携带设备认证信息完成注册和状态恢复。
3. SaaS 为未绑定设备创建设置会话,签发短时手机交接入口。
4. 手机兑换入口并登录账号;服务端保存当前设备上下文,提供有权限的使用者列表。
5. 手机选择使用者并创建绑定申请,此时设备尚未归属于该账号。
6. SaaS 向设备下发当前申请的确认挑战;用户按键后,设备回传对应申请的确认。
7. SaaS 在一次事务内提交绑定、消费申请、增加绑定代数、更新状态版本、写入激活待办。
8. 设备保存绑定并回执;手机读取结果并回执。设置入口按收尾条件关闭。
9. AI 激活任务独立继续;失败、页面关闭或设置会话过期,都不撤销已提交绑定。
必须分别展示三个结果:设备身份已认证、账号已绑定、AI 服务是否可用。SaaS 收到 HTTP 请求成功、设备本地保存成功、真实首音频验证成功,也分别记录。
## 2 功能清单与现有实现对照
“可复用”表示存在相应基础逻辑,不表示已经符合 ONBOARDING-1.1 的报文和全部业务约束。
| SaaS 功能 | 附件要求和用途 | 当前实现 | 需要的工作 |
|---|---|---|---|
| 生产身份与库存 | 按完整设备 ID 和出厂 MAC 唯一登记;返修恢复原记录;密钥轮换留审计 | 运维接口可建档、生成随机 UUID 和密钥、轮换凭据 | 增加生产身份映射、MAC 唯一约束和幂等生产登记;区分库存与首次上线 |
| 设备认证 | 按设备和密钥版本验证 DEVREQ1 HMAC,检查时间、nonce、停用和吊销 | 已有 HMAC、时间窗口、防重放、加密密钥存储、状态限制 | 新增 ONBOARDING-1.1 认证适配;现有签名格式不能直接兼容 |
| 首次可信校时 | 用单设备密钥签名时间挑战,设备验签后再严格使用 HTTPS | bootstrap 返回服务器时间,但须先通过现有认证 | 新增 C01;不能把现有 bootstrap 当作无可信时间时的校时入口 |
| 设备注册与恢复 | 只接受已登记的生产身份;重复注册返回原设备、绑定和激活状态 | 设备由运维创建;bootstrap 更新在线报告并返回绑定 | 新增 C02、挑战消费、业务幂等及完整公共状态 |
| 云端设置会话 | 关联设备、启动、本地会话、期限和流程阶段 | 未发现 setup_session 完整实现 | 新增 C03 和设置会话;已绑定设备只进入恢复模式 |
| 手机入口交接 | handoff 与 verifier 摘要匹配,短时、一次性兑换,生成浏览器会话 | 未发现此交接流程 | 新增 C04、Web exchange 和 HTTPS 入口页 |
| 账号登录与使用者权限 | 短信登录或注册、保留 setup、校验有权管理的老人档案 | 已有 OIDC 登录、平台账号映射、家庭成员权限、使用者档案 | 若严格遵循附件需补短信入口与注册映射;也可复用 OIDC,但须修改双方认可的登录契约 |
| 绑定申请 | 登录后固定设备、账号、使用者、绑定代数和挑战;每设备一条有效申请 | 一次性绑定码表存在,但不绑定某次设备按键挑战 | 新增待确认申请;不能直接把现有 claim_code 当作新 claim |
| 设备确认后提交绑定 | 核验 claim、challenge、digest、按键事件和当前权限后原子提交 | 当前 POST /api/v1/device-claims 提交绑定码后直接写绑定 | 新增 C06;保留并扩展行锁、有效绑定唯一约束与审计 |
| 状态版本和保存回执 | 独立 binding_generation、device_revision、local_generation、state_hash;记录设备与页面 ACK | 已有 device.version、activation_revision、配置 revision | 新增明确的绑定代数和状态快照;现有版本不能直接互相替代 |
| 流程命令与进度查询 | CONFIRM_CLAIM、APPLY_ACTIVATION、UPDATE_STATE、CLOSE_SETUP | 已有配置、重启、诊断、OTA 命令 | 增加流程命令及权限、过期、去重规则;通用命令 ACK 不等于绑定确认 |
| 独立激活任务 | 固定设备供应商身份与任务;保存调用许可、尝试结果、未知状态和对账证据 | 已有平台代注册、供应商凭据加密保存和复用 | 新增任务和尝试记录;统一平台代注册与设备 SDK 注册的路线 |
| 中断恢复与设置收尾 | 页面关闭、断电、回包丢失后按原任务恢复;关闭 setup 不解除归属 | 有一般设备查询、解绑、重置和部分请求幂等基础 | 新增 C07/C10/C11、Web status/ack/cancel 及完整恢复规则 |
| 运维处理和验收 | 查阶段、绑定、ACK、激活和失败原因,处理停用、返修、对账 | 设备运维、状态迁移、审计和通用 outbox 已有 | 增加首次接入诊断视图和激活对账;将绑定事件接入 outbox |
## 3 认证和生产登记的具体要求
### 3.1 区分生产登记与设备首次注册
上一轮提取的 `POST /api/v1/ops/devices` 是运维建档入口。附件的 `POST /api/v1/device/register` 是设备证明已有身份并报告上线的入口。两者调用者、鉴权和数据用途不同,不能替换使用。
生产侧至少保存:设备固定编号、出厂 MAC、型号、硬件版本、凭据版本、受控密钥引用、生产及返修记录。设备注册请求不能仅凭公开 MAC 获取新密钥,也不能让请求方自行指定账号归属。
现有 Create 每次生成新 UUID 和随机 serial_digest,没有按输入 MAC 重复登记的能力。建议保留数据库内部 UUID,新增唯一的工厂编号与 MAC 映射,由新协议在边界解析 `KP01-84FCE6123456` 一类编号;无需为匹配外部编号直接重写全部内部外键。
现有 FACTORY 状态不允许通过通用设备认证。若生产登记先进入该状态,还需明确出厂放行到可认证状态的流程,或为新库存认证设置单独的准入规则,不能让新设备被自己的初始状态永久挡住。
### 3.2 HMAC 契约存在实质差异
| 项目 | 附件 ONBOARDING-1.1 | 当前平台 |
|---|---|---|
| 设备编号 | KP01- 加完整 12 位大写 MAC | UUID |
| HMAC 密钥字节 | 原始 32 字节 device_key | 当前运维 Create 返回 64 位 hex 字符串,并把该字符串的 UTF-8 字节作为 HMAC 密钥 |
| 时间字段 | X-Timestamp-Ms,Unix 毫秒 | X-Timestamp,RFC3339 |
| 密钥版本 | X-Key-Version,参与签名和密钥选择 | 密钥库有版本,但当前请求签名不包含版本头 |
| 业务请求号 | X-Request-ID,参与签名和幂等 | 现有五行签名不包含业务请求号;部分业务另用 Idempotency-Key |
| 签名正文 | DEVREQ1 开头的九行,包含设备 ID、版本、请求号;路径不含 query | 方法、包含 query 的 RequestURI、时间、nonce、body 哈希,共五行 |
| 签名传输 | Authorization: Device-HMAC-SHA256 加小写 hex | X-Signature,Base64url 无填充 |
| 时间容差 | ±120 秒 | 默认 ±5 分钟,可配置 |
| nonce | 16 随机字节的 Base64url,按设备和版本保存至少 5 分钟 | 接受 16 至 128 字符;当前按设备和 nonce 防重放 |
Header 名称的大小写不是差异重点;签名所包含的内容、编码、密钥字节和时间含义才是兼容性问题。
建议以独立协议适配层支持新路径,复用密钥加密存储和设备状态查询。旧设备继续使用旧契约,避免在同一入口中静默尝试不同签名算法。密钥迁移需要显式标记编码与版本,不能把当前返回的字符串自动解码后用于旧接口。
### 3.3 首次校时与注册提交
C01 接收公开 device_id、key_version、boot_id、client_nonce,返回只包含时间及挑战的签名响应。未知设备通用拒绝。挑战 120 秒有效,签名域为 `TIME1`,不签发账号、绑定或供应商凭据。
C02 验证设备请求后,原子消费与当前设备、启动关联的 challenge_id,并提交注册结果。同一 request_id、同一原始 body 的已成功重试应返回匹配结果;不同 body 返回冲突。已消费挑战不能阻止读取同一已提交结果,但不能授权一次新注册操作。
## 4 手机登录交接需要新增的功能
SaaS 必须维护独立的 setup 上下文,不能只把 device_id 放入登录页 URL。一次 setup 关联设备、boot_id、本地 local_setup_id、模式、期限和当前阶段;默认 15 分钟,绝对上限 30 分钟。
handoff 默认 90 秒有效,数据库保存 token 哈希,并绑定 setup 与 code_challenge。兑换时核对 verifier 摘要、过期状态和一次性消费状态,再建立浏览器会话。它只证明进入了某次设备流程,不授予设备所有权。
HTTPS 入口页从 URL fragment 读取 token 与 verifier,立即清理地址,再同源 POST 兑换。入口固定白名单、禁止任意跳转,页面不加载第三方统计脚本,凭据响应禁止缓存。SaaS HTTPS 页面不反向请求设备的本地 HTTP 接口。
登录前后都需保留服务端 setup;登录成功后更新会话身份并防止会话固定。按附件实现 Cookie 时,应配置 Secure、HttpOnly 和适合该跳转链路的 SameSite,并执行 Origin/CSRF 检查。短信需按手机号、IP、浏览器流程限流,约束验证码期限和尝试次数。
现有 OIDC 登录和家庭权限可以作为账号基础,但 OIDC 自带的 PKCE 不等于附件中的设备 handoff。若继续复用 OIDC,仍要实现“设备流程交接”和“登录后继续原 setup”。
新用户还需要能创建或进入家庭、创建或选择使用者。现有家庭与档案接口可复用:`POST /api/v1/households`、`GET/POST /api/v1/households/{id}/subjects`。附件没有完整规定账号首次加入租户和家庭的策略,这部分必须补入实施设计。
## 5 绑定事务与状态同步
### 5.1 一次绑定申请固定哪些数据
| 数据 | 为什么需要 |
|---|---|
| device_id、setup_id | 确定当前设备和操作流程 |
| 登录账号、tenant_id、household_id、subject_id | 确定归属范围和使用者;账号从登录态取得 |
| claim_id | 为一次明确申请提供长期业务去重标识 |
| challenge、expires_at | 限定本次物理确认窗口,默认 120 秒 |
| binding_digest | 固定被确认的账号和使用者内容;目标变化就重建申请 |
| expected_binding_generation | 防止旧申请在设备已经换绑后继续生效 |
| press_event_id | 防止旧按键事件重复确认另一笔操作 |
| 状态、取消与消费时间、提交结果引用 | 处理取消、确认、超时和网络重试竞争 |
服务端检查的是经过设备认证的“指定申请确认”,不是相信浏览器上传 `button_pressed=true`。配网前的按键授权也不能作为登录后绑定申请的确认。
### 5.2 在一次事务中完成绑定
建议事务顺序:锁定设备及申请 → 识别同申请的已提交结果 → 核验当前权限、代数和未过期挑战 → 检查唯一有效归属 → 写入绑定 → 绑定代数增加一次 → 消费 claim → 更新 device_revision → 写入激活 outbox 事件和审计 → 提交。
复用当前 device_binding 的有效记录唯一索引和行锁,同时为待确认申请增加唯一约束。取消与确认并发时以事务提交结果为准:取消未完成申请不能删除已提交绑定。
现有绑定码逻辑可以保留为独立入口,但不能绕过新协议的按键确认。新模式需明确哪些设备允许使用旧绑定入口,以及运维强制分配归属是否属于受控例外,否则只增加一个安全入口并不能保证所有绑定都经过同样规则。
重试判断不仅要比较原目标,还要确认绑定仍是当前有效归属。当前旧 claim 的已使用分支会读取原 used_binding_id;新流程必须补上绑定代数和当前状态检查,避免设备已解绑或换绑后再返回旧状态作为可用配置。
### 5.3 两种版本与两种回执
`binding_generation` 只在归属发生变化时递增;`device_revision` 在对设备公开的业务状态变化时递增。`local_generation` 是设备存储版本,由设备报告。普通网络更新不能增加绑定代数,普通配置 revision 也不能冒充绑定代数。
C07 验证 device_revision、binding_generation、local_generation 和 state_hash,记录设备已保存哪一版状态。Web ack 记录手机已看到哪次绑定结果。二者均不改变 owner;设备保存失败也不能回滚服务端绑定。
前台应分别显示“待按键确认”“账号已绑定,设备保存中”“账号已绑定,AI 服务准备中”“AI 服务待处理”“AI 服务可用”。轮询超时后仍能从账号设备列表恢复查看。
## 6 激活支撑与现有路线差异
### 6.1 绑定与激活分别提交
附件要求:一台设备一个当前 activation_job,固定 activation_id 和供应商 device_name;每次实际调用有 attempt_id。绑定事务只写待办,后台再处理外部服务。现有通用 outbox 可复用,但当前 ClaimDevice 并未写入这一类激活待办。
至少需要以下业务状态:NOT_STARTED、RESERVED、CONTACT_POSSIBLE、REGISTERED_OBSERVED、READY、RECONCILE_REQUIRED、BLOCKED。绑定状态则单独使用 UNBOUND、CLAIM_PENDING、BOUND、TRANSFER_PENDING。
当前 FACTORY/CLAIMABLE/BOUND/PROVISIONING/ACTIVE/LOST/REVOKED 是另一组设备生命周期状态。不能仅靠一张枚举映射表就认定两套状态相同,特别是当前 ACTIVE 并没有附件要求的真实首音频验收含义。
### 6.2 外部结果未知时的恢复
外部调用前持久化“可能已调用”的记录;记录许可原始有效期和调用尝试。超时、断电、回包丢失进入 RECONCILE_REQUIRED,禁止自动换 device_name、释放可能占用的名额或并行再次激活。结果成功也应区分 SDK 注册成功和真实通话验证成功。
现有 Provision 在数据库事务和锁持有期间调用 registrar.Register,然后存储凭据并提交。如果供应商已处理但回包丢失,事务可能回滚,尚无附件所需的持久化未知结果和对账任务。确定性的 device_name 与已保存凭据复用可以减少重复身份,但不能替代完整的外部调用结果恢复。
### 6.3 实施前需要统一供应商凭据路线
附件第 8 章和 E.2 描述向设备下发 ProductSecret,由设备执行动态注册。当前代码把 ProductSecret 保留在 SaaS,由平台注册后只向设备下发 DeviceSecret。这是执行位置与凭据边界的差异,不能用增加几个返回字段掩盖。
实施建议:优先在现有平台代注册方案上补持久化任务、尝试记录和对账,并同步修订附件中的激活契约。若最终明确选择设备执行注册,则按该路线重新设计调用许可、配置封装和结果回执。两种路线的供应商行为都需要针对实际 SDK/接口版本验证,本文不据文档宣称其已通过实机验证。
代码中还有 License 内容导入、分配和 ACK 相关模块;当前主 router 未接入相应 License ACK/分配闭环,不能视为已有 ONBOARDING-1.1 的授权对账能力。附件采用权益或名额管理,也没有定义向设备交付 License 文件。应先统一授权模型,再确定复用范围。
## 7 附件明确要求的云端接口
下列 18 条均为附件规定的目标接口,当前没有同路径路由。生产登记、运维管理以及已有家庭/使用者管理接口不包含在这个数量中。
### 7.1 设备调用 SaaS
除 C01 使用专用时间签名协议外,均按附件 B 使用设备 HMAC 和 HTTPS。表中字段为 body,设备 ID、密钥版本和请求号等还须按契约放入认证头。
| 编号 | POST 路径 | 核心输入 | SaaS 负责输出或提交 |
|---|---|---|---|
| C01 | /api/v1/device/time-challenges | device_id、key_version、boot_id、client_nonce | 签名时间与短时 challenge_id |
| C02 | /api/v1/device/register | challenge_id、boot_id、hardware_model、hardware_revision、firmware_version、sdk_version | 认证已有生产身份;返回当前状态和契约版本 |
| C03 | /api/v1/device/setup-sessions | boot_id、local_setup_id、transport_profile=LOCAL_WEB | setup_id、期限、轮询间隔、状态 |
| C04 | /api/v1/device/handoffs | setup_id、local_setup_id、code_challenge | 一次性 token、期限、固定 HTTPS 入口 |
| C05 | /api/v1/device/poll | setup_id、boot_id、known_revision | 当前状态、有效流程命令、轮询间隔 |
| C06 | /api/v1/device/claim-confirmations | claim_id、challenge、binding_digest、expected_binding_generation、press_event_id | 提交绑定或返回同一已提交结果 |
| C07 | /api/v1/device/state-acks | device_revision、binding_generation、local_generation、state_hash | 保存设备落盘证据及可否收尾 |
| C08 | /api/v1/device/activation-attempts | activation_id、config_version、attempt_id | 持久化可能调用状态,返回 30 秒执行许可 |
| C09 | /api/v1/device/activation-results | activation_id、attempt_id、stage、sdk_result、outcome | 更新注册/通话验收状态或转入对账 |
| C10 | /api/v1/device/activation-acks | activation_id、local_generation、config_version | 保存激活配置落盘回执 |
| C11 | /api/v1/device/setup-close | setup_id、reason、final_revision | 关闭临时流程,保留绑定和激活任务 |
公共状态包含 device_id、device_revision、binding_generation、binding_state、activation_state、next_action、state_hash。C05 的状态恢复权限不能随手机 token 或原 setup 过期而消失;需要时先创建仅用于恢复的新 setup。
### 7.2 手机调用 SaaS
| POST 路径 | 核心输入或上下文 | 用途 |
|---|---|---|
| /api/v1/web/handoffs/exchange | token、verifier | 登录前兑换一次性入口,创建当前 setup 的浏览器会话 |
| /api/v1/web/auth/sms/send | 手机号和当前流程;附件未完整定义字段 schema | 发送登录验证码并限流 |
| /api/v1/web/auth/sms/verify | 手机号、验证码和当前流程;附件未完整定义字段 schema | 验证、登录或注册,更新会话并保留 setup |
| /api/v1/web/claims | elder_id、expected_binding_generation、登录会话 | 创建待设备按键确认的绑定申请 |
| /api/v1/web/setup/status | 浏览器当前 setup | 查询自己的绑定和激活进度 |
| /api/v1/web/setup/ack | 浏览器当前 setup 及收到结果的上下文 | 确认页面已收到结果 |
| /api/v1/web/claims/cancel | 当前 setup 的待确认申请 | 取消待确认申请;不解绑已经归属的设备 |
设备收到的 masked_account 只用于提示核对,不接受它作为认证依据。用户身份从登录会话取得;不能信任浏览器提交的 owner_user_id,也不能允许浏览器仅凭任意 device_id 查询其他家庭的状态。
### 7.3 可复用的当前入口
| 当前接口或模块 | 可复用范围 | 无法直接替代的部分 |
|---|---|---|
| POST /api/v1/ops/devices | 运维建档、初始平台凭据 | 生产 MAC 幂等登记和 C02 设备认证注册 |
| POST /api/v1/ops/devices/{id}/credentials/rotate | 受控凭据更新 | ONBOARDING-1.1 按版本认证和产线恢复协议 |
| GET /device/v2/bootstrap | 在线报告、当前绑定和固件兼容检查 | 首次时间挑战、setup、绑定代数与完整恢复状态 |
| GET /device/v2/config | 配置查询与版本基础 | CFG1 配置、绑定代数和明确的本地保存 ACK |
| POST /api/v1/device-claims | 家庭权限、绑定码、绑定写入与唯一约束 | 登录后的待确认申请及实体确认挑战 |
| GET /device/v2/commands 及命令 ACK | 命令投递和回执基础 | 四种首次接入命令与具体绑定确认语义 |
| POST /device/v3/hardware-agent-credentials:provision | 平台代注册、固定设备名、加密凭据及复用 | 独立激活任务、执行许可、未知结果对账和 READY 验收 |
| binding-impact / binding-change | 当前家庭权限、解绑与变更前检查 | 新确认流程、绑定代数与所有旧入口失效策略 |
| OIDC、家庭和使用者服务 | 账号认证、成员权限、档案管理 | 手机 handoff、setup Cookie、附件指定短信 schema |
## 8 数据模型和后台页面
以下是逻辑记录划分,可按现有结构扩展,不要求每一项都另建一张表。
| 逻辑记录 | 关键数据和约束 |
|---|---|
| 生产库存和凭据 | 唯一工厂 ID/MAC、内部设备 UUID、租户归属、型号、密钥引用及版本、生产/返修状态 |
| 时间挑战 | 设备、版本、boot_id、client_nonce、签发/失效/消费时间及注册结果关联 |
| 设备当前状态 | 独立绑定和激活状态、device_revision、binding_generation、当前任务、最后在线时间 |
| 设置会话和交接入口 | setup/local_setup/boot 关联、模式、权限、绝对期限、token 哈希、verifier 摘要、消费状态 |
| 绑定申请和绑定历史 | 目标账号/家庭/使用者、挑战、digest、按键事件、期限、代数;唯一有效申请和归属 |
| 状态快照和回执 | 状态 hash、设备保存版本、页面看到的结果、ACK 时间;旧版本不能覆盖新版本 |
| 激活任务和尝试 | 固定供应商身份、权益预留、attempt、许可期限、调用阶段、结果证据、待对账原因 |
| 幂等结果和 outbox | 设备/接口/请求号作用域、原始 body 摘要、提交结果;长期业务唯一键;待办重试和消费去重 |
| 审计记录 | 操作者、设备、setup、claim、activation/attempt、旧/新状态及错误码;不记录密钥和验证码 |
用户侧至少需要:入口恢复页、登录页、家庭/使用者选择页、等待按键确认页、绑定完成及设备保存状态、AI 服务进度、正常账号设备列表。
运维侧至少需要:按工厂编号/MAC 查库存与设备、出厂放行与凭据轮换、首次接入阶段诊断、当前绑定及历史代数、设备/页面 ACK 状态、激活异常与人工对账记录、停用和报失处置。
## 9 附件在当前 SaaS 中还需明确的设计点
1. **租户和 owner 映射。** 当前设备、家庭和档案受租户约束,归属主要通过 household/subject 表达。附件没有规定新手机号注册到哪个租户、能否认领其他租户库存,以及 owner 是家庭还是单一账号。建议按生产归属解析租户,并继续验证家庭管理权限;不要直接让手机号或 elder_id 决定租户。
2. **身份编码迁移。** 外部 KP01 编号与现有 UUID 保持稳定映射;产线、认证、售后和旧客户端不得各自生成新身份。
3. **绑定代数的变更规则。** 附件规定归属变化递增,但需要进一步固定“解绑后再绑定”和“一步转移”的递增及历史记录规则。所有写入口必须统一。
4. **普通重新配网与恢复出厂。** 当前 /device/v3/factory-reset 会解除绑定并生成新绑定码。附件规定普通重配网保留 owner,转让走原账号授权。因此普通重配网不能调用此接口,完整恢复出厂的归属权限也需要单独定规则。
5. **激活执行位置与授权模型。** 统一平台代注册还是设备 SDK 注册、ProductSecret 的位置、名额与供应商权益的对应关系,以及什么证据足以解除未知结果状态。
6. **接口详细 schema。** 短信输入、取消目标、浏览器 ACK 的版本匹配、部分恢复错误及晚到结果规则仍需写入 OpenAPI。公共约定要求变更请求带 X-Request-ID,浏览器这些写操作也应明确其用法。
7. **状态快照和 ACK。** 明确 device_revision 对应的历史状态保留策略;当前状态继续推进时,设备应同步最新版本,不能把旧 ACK 写成新版本已保存。
8. **存量入口。** 现有绑定码、运维分配、解绑转移和恢复出厂均会影响归属。新协议不能只覆盖新页面而遗漏其他写入口。
## 10 建议开发顺序与验收
第一阶段先完成认证与绑定:生产身份映射 → 新鉴权与时间挑战 → 注册和公共状态 → setup/handoff → 登录与使用者选择 → 待确认申请 → 设备确认事务 → 两侧回执与收尾。此阶段可返回“已绑定,AI 服务待开通”,不阻塞于真实供应商联调。
第二阶段补齐激活:绑定 outbox → 固定激活任务与身份 → 调用尝试和许可 → 结果上报与对账 → 激活配置 ACK → 首音频验收后的 READY。
第三阶段完成运营闭环:停用和密钥轮换、返修、原账号解绑与新账号确认、旧代数隔离、失败恢复入口、诊断视图及生产环境限流监控。
必须覆盖的验收结果:
- 同 MAC/工厂 ID 重复生产登记和重复上线,不增加设备副本,也不清空已有绑定。
- 错密钥、错版本、过期时间、重放 nonce 被拒绝;同请求号不同 body 返回冲突。
- handoff 仅能兑换一次,过期不能复活;登录和浏览器切换后可恢复正确设备上下文。
- 无设备确认不能绑定;双账号并发仅一条有效申请和一个有效归属。
- 旧 challenge、旧按键、被取消 claim、旧绑定代数不能建立新归属。
- 绑定提交后回包丢失,返回同一有效结果;设备保存失败只补写和 ACK,不撤销绑定。
- 页面关闭、setup 到期或热点关闭后,设备仍能恢复原激活任务。
- 供应商结果未知保留原任务、设备名和可能占用的权益;不自动释放后再次分配。
- SDK 注册成功与真实通话 READY 分开;授权不足保留账号绑定。
- 普通重配网保留归属;正式解绑或转移使旧会话、旧申请和旧用户配置失效。
## 11 当前代码依据
- [实际路由与设备鉴权分组](E:/Codex/story/platform/internal/httpapi/router.go:297)
- [运维登记设备和生成平台凭据](E:/Codex/story/platform/internal/opsdevice/service.go:244)
- [当前设备 HMAC 验证和签名正文](E:/Codex/story/platform/internal/deviceauth/verifier.go:69)
- [设备凭据加密存储与轮换](E:/Codex/story/platform/internal/deviceauth/database_secret.go:115)
- [bootstrap 的现有状态字段和报告](E:/Codex/story/platform/internal/device/repository.go:32)
- [当前提交绑定码后直接绑定的逻辑](E:/Codex/story/platform/internal/saas/device_claim.go:27)
- [有效设备绑定唯一约束](E:/Codex/story/platform/migrations/000005_device_conversation.up.sql:65)
- [当前 claim 数据结构](E:/Codex/story/platform/migrations/000007_device_claim.up.sql:3)
- [当前设备生命周期状态](E:/Codex/story/platform/internal/deviceactivation/state.go:15)
- [当前解绑和转移事务](E:/Codex/story/platform/internal/saas/device_binding_service.go:67)
- [当前命令类型约束](E:/Codex/story/platform/migrations/000011_device_command.up.sql:8)
- [平台代注册与供应商凭据保存](E:/Codex/story/platform/internal/hardwareprovision/service.go:127)
- [License 模块](E:/Codex/story/platform/internal/hardwarelicense/service.go:250)
- [恢复出厂解除绑定](E:/Codex/story/platform/internal/devicereset/service.go:168)
- [现有前端 OIDC 登录](E:/Codex/story/platform/web/src/auth/oidc.ts:6)
- [通用 outbox 执行基础](E:/Codex/story/platform/internal/outbox/worker.go:1)