id, title, phase, deps, status, created, context_ref, work_branch, write_paths
id
title
phase
deps
status
created
context_ref
work_branch
write_paths
T-226
Go ERP 会话管理与 Admin 验证码登录
2
DONE
2026-07-29
d62a4af
null
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 账号;进程重启后会话失效,
需要人员重新登录。
方案
ERP base URL、用户名和密码只从后端启动环境读取;不读取 .env,不保存到 SQLite、
Cookie、浏览器、普通日志或 API 响应。
Admin 连接页显示匿名会话状态,可请求一次性验证码图片并输入验证码登录。图片响应
必须 no-store,浏览器只得到验证码图片和短期 ticket,不能得到 ERP Cookie/JWT。
会话管理器为 Cookie jar、token、用户最小标识和 ticket 建立串行锁;查询、验证码
和登录不能并发改变同一会话。
账号/密码未配置、验证码过期、登录拒绝、会话过期和 ERP 不可用均返回稳定匿名错误。
首版只保留内存会话;加密持久化会话须另立任务,不引入 Redis。
验收要点
边界
不自动 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。