diff --git a/T-226.-.md b/T-226.-.md new file mode 100644 index 0000000..32aa37f --- /dev/null +++ b/T-226.-.md @@ -0,0 +1,81 @@ + +> 同步来源:[`docs/tasks/T-226.md`](/chengma/mroubao/src/commit/afc651f75a3abc2676bb13aa8a80f6aa6a25a72e/docs/tasks/T-226.md) · commit `afc651f75a3a` + +--- +id: T-226 +title: Go ERP 会话管理与 Admin 验证码登录 +phase: 2 +deps: + - T-225 +status: DONE +created: 2026-07-29 +context_ref: d62a4af +work_branch: null +write_paths: + - docs/tasks/T-226.md + - docs/04-architecture.md + - docs/api.md + - docs/routes.md + - docs/current-state.md + - backend-api/internal/config/** + - backend-api/internal/platform/shunyunbao/** + - backend-api/internal/transport/httpapi/** + - backend-api/internal/transport/webui/** + - backend-api/cmd/api/** +--- + +## 问题 / 背景 + +直接 Go 查询需要让后端在同一 ERP 会话中获取验证码、登录、验证状态和发起查询。账号 +密码不能输入到普通 Admin 表单,Cookie/JWT 不能发给浏览器;同时单机验证版不需要为 +恢复会话额外部署 Redis。 + +## 关联需求与交互 + +- 功能:F-011。 +- 用户故事:US-011。 +- 交互:IX-012 增加 ERP 连接状态、获取验证码和提交验证码。 +- 架构:一个受互斥保护的 Go 会话管理器服务一个受配置 ERP 账号;进程重启后会话失效, + 需要人员重新登录。 + +## 方案 + +1. ERP base URL、用户名和密码只从后端启动环境读取;不读取 `.env`,不保存到 SQLite、 + Cookie、浏览器、普通日志或 API 响应。 +2. Admin 连接页显示匿名会话状态,可请求一次性验证码图片并输入验证码登录。图片响应 + 必须 `no-store`,浏览器只得到验证码图片和短期 ticket,不能得到 ERP Cookie/JWT。 +3. 会话管理器为 Cookie jar、token、用户最小标识和 ticket 建立串行锁;查询、验证码 + 和登录不能并发改变同一会话。 +4. 账号/密码未配置、验证码过期、登录拒绝、会话过期和 ERP 不可用均返回稳定匿名错误。 +5. 首版只保留内存会话;加密持久化会话须另立任务,不引入 Redis。 + +## 验收要点 + +- [x] 配置缺失、验证码获取、错误/过期验证码、登录成功、会话过期和并发请求有单元/HTTP 测试。 +- [x] Admin 页面在桌面和手机视口显示状态、验证码和可修复错误,不显示密码、Cookie、JWT 或验证码文本。 +- [x] 会话请求和查询共享同一受控 Cookie jar;进程重启后明确要求重新登录。 +- [x] `go test ./...`、`go vet ./...` 通过;未访问线上 ERP。 + +## 边界 + +- 不自动 OCR、猜测或绕过验证码。 +- 不实现多 ERP 账号、多租户、Redis 或凭证 Web 编辑。 +- 不切换货运同步查询源;属于 T-227。 + +## 执行记录 + +- 2026-07-29:由 T-225 依赖创建,等待协议契约完成。 +- 2026-07-29:开始实施;T-225 已由 `c2f340d` 完成,当前仍未访问线上 ERP。 +- 2026-07-29:新增 `SessionManager`,以同一受锁 Cookie jar 完成验证码、登录和 + `/am/user/get` 校验;只保存内存会话,验证码 ticket 默认 5 分钟后失效。账号/密码仅由 + `CMROUBAO_SHUNYUNBAO_*` 环境读取,未配置不会阻止其他后端功能启动。 +- 2026-07-29:新增 ADMIN 的 `/erp` 连接页和 `/api/v1/erp-session*` 接口;所有写接口 + 继续受 ADMIN CSRF middleware 保护。浏览器页面只输入验证码,图片和 ticket 均 `no-store`, + 不返回 ERP Cookie、JWT、用户资料、密码或原始错误正文。 +- 验证:在 `backend-api/` 执行 `$env:GOTOOLCHAIN='local'; go test ./...; go test -race ./...;` + `go vet ./...; go build ./cmd/api; go build ./cmd/migrate; go build ./cmd/authctl`,全部通过。 + 会话/HTTP/SSR 使用 `httptest` 伪 ERP;未访问线上 ERP。 +- UI smoke:隔离 SQLite 上以 `smoke-admin` 登录实际 Gin 服务,Chrome 以 1440x900 和 + 390x844 验证 `/erp` 未配置状态无横向溢出;截图只写入系统临时目录,未进仓库。 +- 未验证项:真实 ERP 凭证、人工验证码和厂商授权检查有意留给部署前人员操作;T-227 + 才把会话接入货运同步 source。