forked from xiaohei/taiji-AI-PAD
docs(heicode): §16-§20 端到端全通 + ① APIM 验掉 + D-5 发信收口
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -438,3 +438,153 @@ APIM 对 landing 这个 **GET** 的 operation 必须满足——否则浏览器
|
||||
|
||||
## 15.4 一句话
|
||||
**request/verify 可即刻联调;landing 的 ① APIM 我方跟进;只差 HM 回 §15.3 一句(联调发信走 A 还是 B)。**
|
||||
|
||||
---
|
||||
|
||||
# 16. HM owner @zsbgnw12:经 HM 生产代理实测三端点已通(2026-06-09)
|
||||
|
||||
> 收到 §14/§15。HM 侧立即对**生产**做了端到端实测:客户端 → `https://code.xinghanlab.com/api/heicode-auth/...`(HM 同源代理)→ APIM → mcp-server 三端点。结果如下(真实返回)。
|
||||
|
||||
## 16.1 实测结果(HM 代理 → APIM → mcp-server,均生产)
|
||||
- `POST /api/heicode-auth/api/auth/magic-link/request` body `{"email":"hm-integ-test@example.com"}`(**未注册邮箱**)→ **200** `{"success":true,"data":{"request_id":"e1134b6c-…","state":"42YbF-…","expires_in_sec":600}}`。✅ 防枚举生效(未注册也 200)、HM `{success,data}` 信封正常、`state` 已下发。
|
||||
- `POST …/magic-link/verify` body `{"code":"bad…","state":"x"}` → **401** `{"detail":"登录凭证无效或已过期"}`。✅ 坏 code 正确拒绝。
|
||||
- `GET …/magic-link/landing?token=bad&state=x` → **400 + `text/html`** 「链接无效」页。✅
|
||||
- ⇒ **HM 同源代理对三端点全部可达、零改动**;`request`/`verify` **联调即刻可用**。
|
||||
|
||||
## 16.2 对 ① APIM 透传的范围收窄(实测旁证)
|
||||
- 上面 landing 的**失败分支 HTML 已经成功经 APIM 透回浏览器**(拿到了 400 + `text/html`)。⇒ APIM 放行该 GET、且能透传 `text/html` 这两点**已被实测证明**。
|
||||
- 所以 ① 现在**唯一未验证的只剩「成功路径的 `302 Location: heicode://auth/callback?...`」是否被 APIM 原样透回**(非 http scheme 的 Location)。请你方 APIM owner 重点只验这一条;其余(放行 GET / 透 HTML)实测已 OK。
|
||||
|
||||
## 16.3 HM 回 §15.3(联调发信 A/B)
|
||||
- HM 也倾向 **(A) 联调期临时开真发信**(最接近真实链路)。但「D-5 正式签字前先开发信用于**联调**」需**产品点头**——**HM owner 正在 #19 跟产品确认**,确认后回写本节并请运维置 `MAGIC_LINK_EMAIL_ENABLED=true`(测试邮箱)。
|
||||
- 在产品确认前的过渡:可先用 **(B)** 从 mcp-server pod 日志(DEBUG)取链接做纯功能验证,不阻塞 `request`/`verify` 对接与回跳后 `verify` 换 token 的逻辑联调。
|
||||
|
||||
## 16.4 HM 并行推进
|
||||
- 客户端 cc-haha:邮箱登录 UI + `heicode://auth/callback` 深链注册转发 + `state` 比对 + 同源代理调 `request`/`verify`,对**生产**端点先行(landing 成功回跳待 ① 落定)。
|
||||
- D-5 邮件基建签字:HM 在 #19 追产品。
|
||||
|
||||
## 16.5 一句话
|
||||
**HM 代理→APIM→mcp 三端点实测全通,request/verify 联调已开跑;① 只剩「heicode:// 302 透传」一条待你方 APIM owner 验;§15.3 HM 倾向 A、待产品点头。**
|
||||
|
||||
---
|
||||
|
||||
# 17. HM 提议:联合端到端「模拟真实」测试(一次性,不需真发信,顺带验掉 ①)(2026-06-09)
|
||||
|
||||
> 目标:不等产品签字(D-5)、不真发信,**就把"邮箱→链接→landing→302→code→verify→登录产物"整条链跑通一遍**,并**用真实成功路径验掉 ① 的唯一悬念**(APIM 是否原样透回 `heicode://` 302)。
|
||||
|
||||
## 17.1 为什么需要你们配合一步
|
||||
magic-link `token` 按设计**只在邮件里 + 你们 Redis `magic_link_token:{token}`**;`request` 响应只回 `{request_id, state}`,**不回 token**。所以 HM 单方拿不到 token,走不到成功路径。**只要你们把一个有效 token 露出来一次,后面全程 HM 驱动。**
|
||||
|
||||
## 17.2 联合流程(用文档已有测试账号 `55@55.com`,role=user)
|
||||
1. **HM 调** `POST .../magic-link/request {email:"55@55.com"}` → 记下返回的 `state`(token 同时进你们 Redis,TTL 600s)。
|
||||
2. **请 mcp 立即**(10 分钟内)从 Redis 读出刚生成的 token(`KEYS magic_link_token:*` 或 mock 的 DEBUG 日志行),把 **token 值**回写本节(`55@55.com` 是公开测试账号,token 一次性、读后我马上消费)。
|
||||
3. **HM 用真实 token 打成功路径**(经 APIM,`curl -i` 不跟随):
|
||||
`GET .../magic-link/landing?token=<你给的>&state=<步骤1的state>` → **期望 `302` + `Location: heicode://auth/callback?code=...&state=...`**。
|
||||
- ✅ 拿到带 `heicode://` 的 302 → **① 当场验掉**(APIM 能原样透回非 http Location),D-4 定 APIM,无需回退方案2。
|
||||
- ❌ 302 被 APIM 吞/改写/Location 丢失 → **① 证伪**,按 §9.3 回退方案2(HM 托管落地页)。
|
||||
4. **HM 再打** `POST .../magic-link/verify {code:<上一步302里的code>, state}` → **期望 `200` + `{token, refreshToken, user{id,name,email,role,channelId}}`**,且与 `/api/auth/login` 逐字段一致 → **登录产物等价 + EU/计费零改动 当场坐实**。
|
||||
|
||||
## 17.3 备选(更"真实",但需产品点头)
|
||||
若产品同意 §15.3-A:运维把 `MAGIC_LINK_EMAIL_ENABLED=true` 指向一个**测试邮箱**,则连"收真信→点链接"都真实跑;否则用 17.2 的"露 token"即可完成功能与 ① 验证。
|
||||
|
||||
> **请 mcp 配合 17.2 第 2 步(露一个 token)**,或告知更方便的露出方式。HM 这边随时可发起步骤 1、并在拿到 token 后立即跑 3/4 把结果(尤其 ① 的 302)回写本文件。
|
||||
|
||||
## 17.4 ⏱ HM 已发起步骤1(实时,2026-06-09)
|
||||
HM 刚对 `55@55.com` 调了 `request`,生产返回:
|
||||
- `request_id` = `9b93f06d-a2de-4ee5-8929-6c52708e3387`
|
||||
- `state` = `c2IJAScWGyMhl5FYrprprA`
|
||||
- `expires_in_sec` = 600(**约 10 分钟内有效**)
|
||||
|
||||
→ **请 mcp 立即从 Redis 读出对应 token**(`KEYS magic_link_token:*` 取最新一个,或 mock DEBUG 日志里 `55@55.com` 那条链接里的 token),把 **token 值回写到本节下方**。HM 拿到后立即用 `state=c2IJAScWGyMhl5FYrprprA` 跑 `landing`(`curl -i`)验 ① 的 `heicode://` 302,再 `verify` 验登录产物。**若超过 10 分钟,HM 会重发并更新本节的 request_id/state。**
|
||||
|
||||
mcp 回填 token:`uoJTHO7nbM4tGNI-mTe58OWkVQjmMEwjcXc4gOqL7ZU`(已消费,见 §18 结果)
|
||||
|
||||
---
|
||||
|
||||
# 18. HM owner @zsbgnw12:联合「模拟真实」端到端测试 **全链路通过**(2026-06-09,真实返回)
|
||||
|
||||
> 用 §17.2 流程 + mcp 露出的 token(`uoJTHO7n…`)对 **生产** 完整跑了一遍 magic-link 链路。**① 当场验掉,登录产物等价当场坐实。** 全部真实返回如下。
|
||||
|
||||
## 18.1 步骤3 — landing 成功路径(经 APIM,`curl -i`)→ ✅ **① 透传通过**
|
||||
```
|
||||
GET https://apimtaiji.azure-api.net/api/mcp/api/auth/magic-link/landing?token=uoJTHO7n…&state=c2IJAScWGyMhl5FYrprprA
|
||||
→ HTTP/1.1 302 Found
|
||||
Location: heicode://auth/callback?code=7MPE4UZR7AYwhiDC4ghvhpzWKfGy3nBR&state=c2IJAScWGyMhl5FYrprprA
|
||||
X-Frame-Options: DENY / X-Content-Type-Options: nosniff
|
||||
```
|
||||
**结论:APIM 原样透回了非 http 的 `Location: heicode://...`,302 未被跟随/改写/吞掉。① 的唯一悬念解决 → D-4 定 `方案1-APIM`,无需回退方案2。** state 原样带回、code 一次性。
|
||||
|
||||
## 18.2 步骤4 — verify(经 HM 同源代理)→ ✅ **登录产物等价**
|
||||
```
|
||||
POST https://code.xinghanlab.com/api/heicode-auth/api/auth/magic-link/verify {code:7MPE4U…, state:c2IJAS…}
|
||||
→ 200 {success:true, data:{token, refreshToken, user}}
|
||||
token claims: sub=b00a7b8e-… email=55@55.com role=user channelId=6e6fc470-… type=access
|
||||
exp-iat = 86400s(24h)✅
|
||||
refresh claims: type=refresh, exp-iat = 604800s(7天)✅
|
||||
user: {id:b00a7b8e-…, name:"55", email:"55@55.com", role:"user", channelId:"6e6fc470-…"}
|
||||
```
|
||||
**与 `/api/auth/login`(《登录接口对接文档》§2.3/§3.1)的信封、JWT claims、TTL 逐字段一致** → 不引入新会话/新计费分支,**EU/计费零改动**坐实(§1.3/§12.3 验证完成)。
|
||||
|
||||
## 18.3 整链状态
|
||||
`request → (token) → landing 302 heicode:// → verify → 登录产物` **生产全通**。功能层面 **magic-link 后端 + HM 代理 + APIM 透传 + 登录等价 = 全部验证通过**。
|
||||
|
||||
## 18.4 真正剩余(仅这两条,与功能无关)
|
||||
1. **真实发信(D-5)**:现 `MAGIC_LINK_EMAIL_ENABLED=false`(本次用露 token 绕过)。真发信需产品对邮件基建签字 → 运维置 true。
|
||||
2. **客户端 cc-haha**:邮箱登录 UI + `heicode://auth/callback` 深链注册转发 + state 比对 + 调 request/verify(HM 侧客户端代码,待实现)。
|
||||
|
||||
> **一句话:模拟真实测试整条链生产跑通,① 已验掉,契约 D-4 定 APIM。只差"真发信签字 + 客户端 UI"两件非功能项。**
|
||||
|
||||
---
|
||||
|
||||
# 19. HM owner @zsbgnw12 — #19 收口状态 + 仅剩 D-5 待 mcp-server 推进(2026-06-10)
|
||||
|
||||
> HM 侧把工单 #19(magic-link 邮箱登录)列为「等 mcp-server + 邮件基建」。功能链路(§18)已生产验证全通,**无契约/功能阻塞**。盘点后 mcp-server 侧只剩 **D-5 真实发信** 一件。
|
||||
|
||||
## 19.1 现状(已确认,无需再动)
|
||||
- request → landing 302 `heicode://auth/callback` → verify 登录产物,**生产全链路验证通过**(§18.1–18.3)。
|
||||
- 登录产物与 `/api/auth/login` **逐字段等价**(JWT claims / TTL / 信封)→ **EU/计费零改动**。
|
||||
- 契约 **D-4 = APIM 方案1**(§16/§18.1 已验)。密码登录并存、不受影响(§1)。
|
||||
|
||||
## 19.2 ⭐ 还需 mcp-server 推进/回复(仅 D-5,**#19 卡点**)
|
||||
当前 `MAGIC_LINK_EMAIL_ENABLED=false`(测试期靠 response 露 token 绕过)。要真正发链接给用户,需 mcp-server 把发信打通。请在本节下方回:
|
||||
1. **邮件/通知基础设施 owner 是谁**(负责账号/域名/配额/合规)?
|
||||
2. **走哪家发信**(SMTP / SES / SendGrid / 阿里云邮件…)?凭据走 **secret_ref / 密钥保管库,不进代码/日志/Markdown**。
|
||||
3. flip `MAGIC_LINK_EMAIL_ENABLED=true` 的**前置清单**(发信域名验证 / 退信处理 / 按 email 频率限制 / 链接 TTL 复核)。
|
||||
4. 确认**除 D-5 外 mcp-server 侧无其它阻塞**(三端点 + landing + verify 已冻结且生产可用)。
|
||||
|
||||
## 19.3 HM 侧并行(不阻塞你们)
|
||||
- 客户端 cc-haha:邮箱登录 UI + `heicode://auth/callback` 深链转发 + `state` 比对 + 调 request/verify(HM/客户端侧代码,自推)。
|
||||
|
||||
## 19.4 请回复
|
||||
mcp-server 在本节下方回 **§19.2 的 1–4**(尤其邮件基建 owner + 前置清单),HM 据此推进 #19 收尾;真发信开关由对应 owner 在前置满足后置 true。
|
||||
|
||||
---
|
||||
|
||||
# 20. mcp-server 回复 §19.2(D-5 发信收口,2026-06-10)
|
||||
|
||||
> 逐条回 §19.2 的 1–4。**发信通道经我方拍板:就用现有 189.cn SMTP,送达率/企业用户收不到的问题暂不考虑**(作为已知接受风险记录在案,见 Q2/Q3)。
|
||||
|
||||
## Q1 邮件基建 owner
|
||||
- **暂无独立的"邮件基建 owner"**;过渡期由 **mcp-server 运维**以现有 189.cn 通道承载发信。正式 owner / 合规签字若后续要正式运营再由产品指认——但**不阻塞本次开闸**(已接受 189.cn 现状,见 Q2)。
|
||||
|
||||
## Q2 走哪家发信
|
||||
- **维持现有 189.cn SMTP**:`smtp.189.cn:465 (SSL)`、发件 `taijiagent@189.cn`,**复用** `app/email_verification.py` 的发信通道(magic-link 不另起炉灶)。凭据 `SMTP_PASSWORD` 走 k8s secret `taiji-secrets` 的 `secretKeyRef` 注入——**不进代码 / 日志 / Markdown**(符合 §1.4 与组织密钥规则)。
|
||||
- ⚠️ **已知接受风险(经决策)**:189.cn 为运营商邮箱,**对企业/海外用户的送达率、进垃圾箱风险本期不处理**;无 SPF/DKIM/DMARC 域名背书、无退信(bounce)回收。本期仅满足"能发出链接"。后续若要正式运营再评估换 SES/SendGrid。
|
||||
|
||||
## Q3 flip `MAGIC_LINK_EMAIL_ENABLED=true` 前置清单
|
||||
| 项 | 状态 |
|
||||
|---|---|
|
||||
| 按 email 频率限制(60s/邮箱,独立键) | ✅ 已实现 `app/magic_link.py` `check_email_rate_limit` |
|
||||
| 链接 TTL:token 600s / code 120s / 一次性 | ✅ 已实现 |
|
||||
| 防枚举(限流前置、存在/不存在一视同仁) | ✅ 已实现 |
|
||||
| SMTP 凭据 `SMTP_PASSWORD` 注入 | ✅ 生产已注入(secret `taiji-secrets`) |
|
||||
| 发信域名验证(SPF/DKIM/DMARC)/ 送达率 | ⏸ **本期不做**(Q2 接受风险) |
|
||||
| 退信(bounce)处理 | ⏸ **本期不做**(Q2 接受风险) |
|
||||
- **开闸动作**(满足前置后由运维执行):确认 189.cn 的 `SMTP_PASSWORD` 有效 → 把 `k8s/prod/configmap.yaml` 的 `MAGIC_LINK_EMAIL_ENABLED` 置 `true` → 滚动重启 mcp-server 生效。`request` 即对**已存在的 role=user** 邮箱真发链接。
|
||||
|
||||
## Q4 除 D-5 外有无其它阻塞
|
||||
- ✅ **无功能/契约阻塞**。三端点 + landing + verify 已冻结、生产可用、登录产物等价已生产验证(§18,且 token 被成功路径一次性消费已独立核实)。契约 D-4=APIM 定稿。
|
||||
- 备注(非阻塞,我方收尾项):§16–§20 文档 + 两个 k8s yaml(`MAGIC_LINK_EMAIL_ENABLED` 注入 + 镜像 tag 升 `arm64-v2`)将提交并推到 Gitea `feature/chenchen`,使远端与"已部署 arm64-v2 + 开闸配置"对齐。
|
||||
|
||||
## 一句话
|
||||
**发信定 189.cn(送达率本期不考虑、已接受);开闸前置除"运维置 `MAGIC_LINK_EMAIL_ENABLED=true`"外均已就绪;mcp-server 侧无其它阻塞。** HM 可据此在 #19 收尾,真发信由运维按上表开闸。
|
||||
|
||||
Reference in New Issue
Block a user