--- id: T-201 title: 管理员登录与会话 phase: 2 deps: [T-004, T-005] status: DONE created: 2026-08-04 vikunja_task_id: 26 context_ref: 80ed9b7 work_branch: task/t-201-admin-session needs_device: false needs_human_review: false write_paths: - docs/tasks/T-201.md - admin/cmd/server/main.go - admin/internal/config/** - admin/internal/server/** - admin/internal/auth/** - admin/internal/transport/webui/** - admin/go.mod - admin/go.sum - admin/README.md --- ## 问题 / 背景 采购服务已有 Go/Gin/SQLite 骨架和核心模型,但没有管理员会话。T-201 与真机规格字段无关,可在 T-103 进行时并行。 ## 关联需求与交互 F-013、US-007;路由 GET/POST /login、POST /logout、受保护的 GET /tasks 空壳;沿用已确认采购服务原型。 ## 方案 1. 启动时从环境变量读取管理员用户名、bcrypt 密码哈希、至少 32 字节 session secret;缺失或无效时明确失败,不提供默认凭据,不打印秘密。 2. 使用签名会话和 CSRF;登录成功轮换会话,Cookie 为 HttpOnly、SameSite,Secure 由显式配置控制。 3. return_to 仅接受 /tasks 及其子路径,拒绝绝对 URL、双斜杠、反斜杠和其他站内路径。 4. 实现登录、登出与受保护的任务空壳;/healthz 保持公开。 5. 不改数据库 schema,不实现设备 Bearer、建单、试选、授权、提交或付款。 ## 验收要点 - 覆盖未登录跳转、成功登录与会话轮换、统一失败错误、CSRF 拒绝、登出失效和开放重定向拦截。 - 无默认账号/密码/密钥,日志与响应不泄露凭据。 - go test ./...、go vet ./...、go build ./...、上下文校验与 diff-check 通过。 ## 执行记录 ### 2026-08-04T06:58:30Z · ila 2026-08-04 T-201 实现与主审完成:提交 47c0844 新增强制环境配置、bcrypt 校验、HMAC-SHA256 签名进程内 session、随机 CSRF、登录轮换、登出撤销、受保护 /tasks 空壳和无外部资源的 SSR 登录页。主 agent 首轮退回 /tasks/.. 返回路径绕过、含 CSRF 页面缺安全响应头、Cookie 篡改测试概率失效三项;修正后独立复跑 go test ./...、go test -race ./...、go vet ./...、go build ./...、上下文校验与 diff-check,全部通过。实现未包含建单、试选、真机字段、授权、提交或付款;T-201 验收通过。 ### 2026-08-04T07:03:54Z · ila 集成门禁补充:T-201 分支已合入 main@88d8f77(含 T-103 最新安全诊断),随后在独立 Windows worktree 运行完整 init.ps1,admin test/vet/build、client 78 项测试/compileall、editable install 与 agent-context 校验全部通过。首次运行因 120 秒工具超时中断在大体积 PySide6 依赖安装,未产生代码或证据问题;复用已建 venv 后完整成功。 ## 边界 - 启动配置只接受显式环境变量中的管理员用户名、bcrypt 密码哈希和至少 32 字节 session secret; 不得内置开发默认值、明文密码或密钥,不得打印、回显或提交凭据。 - 本任务只实现 `/login`、`/logout`、受保护的 `/tasks` 空壳和保持公开的 `/healthz`;不实现建单、 查询、批量开始试选、设备 Bearer、真机自动化或任务状态流转。 - 不增加或修改数据库 schema,不读写 `spec_trials`、授权或 `order_submissions`,不实现任何提交订单、 付款、免密支付、先用后付或资金控件代码。 - 页面和测试不得夹带机器实际规格、规格面板价格、截图、证据哈希或任何 PDD 页面判据;这些仍等待 T-103 真机结论。 - `return_to` 必须是 `/tasks` 或其子路径;绝对 URL、`//`、反斜杠、编码绕过和其他站内路径均拒绝。