# 50 Admin:实现首次管理员初始化与网页登录 - 类型:需求 - 父级大工单:#14 - 所属 MVP / 版本:#15 / MVP - 状态:已完成 - 日期:2026-08-09 - Gitea 工单: ## 背景与目标 Admin 原有全部网页都可匿名访问,也没有管理员初始化、登录或退出能力。本任务 建立最小且完整的网页登录边界:首次运行由操作员创建唯一的首位管理员,随后 所有业务网页必须凭服务端 Session 访问,同时保持 Client API 的现有调用方式不变。 ## 最终方案 - 新增 v6 迁移,在末尾追加 `users` 和 `web_sessions`,未改写 v1–v5;用户名 使用不区分大小写的唯一约束,角色和状态使用固定值约束。 - `/setup` 仅在用户表为空时开放;创建管理员前在写事务内再次检查,两个并发 初始化请求最多一个成功。入口一旦关闭,即使账号以后禁用也不会重新开放。 - 密码使用 bcrypt 默认成本哈希,服务层校验至少 8 个字符和 bcrypt 的 72 字节 上限;数据库、页面及日志均不保存或回显明文密码。 - 登录成功生成 32 字节密码学随机 Token,浏览器 Cookie 保存原文,数据库只保存 SHA-256。Session 固定 12 小时有效,退出和账号禁用会使旧 Session 失效。 - 认证 Cookie 使用 `HttpOnly`、`SameSite=Lax`、`Path=/`,HTTPS 请求自动增加 `Secure`;登录后的 `next` 只接受本站绝对路径,阻止开放重定向。 - Web 公开页和业务页都经过 CSRF;认证中间件只挂业务网页路由组。Client API 继续注册在独立路由组,不要求网页登录 Cookie,也不经过浏览器 CSRF。 - 增加独立初始化页和登录页;业务导航显示当前用户名,并用 POST 表单退出。 实际实现与工单确认方案一致。采购员管理、密码重置和登录限速留给 #51,Client API Key 认证留给 #52,本任务没有扩大范围。 ## 改了哪些 - `admin/repository/db.go`、`admin/model/model.go`、`admin/repository/user.go`: v6 数据结构、用户与 Session 数据访问及初始化事务。 - `admin/service/auth.go`:首次初始化、bcrypt 密码校验、登录认证、Session 哈希与退出。 - `admin/handler/web/auth.go`、`admin/handler/web/web.go`:公开认证页、业务页中间件、 Cookie、本站回跳和退出路由。 - `admin/templates/auth/`、`admin/templates/partials/header.html`、 `admin/static/css/app.css`:初始化、登录和已登录导航界面。 - `admin/auth_integration_test.go`、`admin/handler/web/auth_test.go`、 `admin/service/auth_test.go`、`admin/repository/migrate_test.go`、`admin/main_test.go`: 迁移、并发、安全属性、HTTP 完整流程和回归测试。 - `docs/admin/03-data-model.md`:将 v6 用户与 Session 模型从规划更新为已实现。 ## 验收结果 | 验收标准 | 结果 | |---|---| | v6 可从全新库和历史结构升级,且未改写旧迁移 | 通过 | | 首次初始化并发请求最多创建一个管理员 | 通过 | | 初始化完成后 `/setup` 永久关闭 | 通过 | | 密码只保存 bcrypt 哈希,错误凭据统一提示 | 通过 | | Session 原文不入库,固定 12 小时过期 | 通过 | | 退出、过期和账号禁用后旧 Session 失效 | 通过 | | Cookie 具备 HttpOnly、SameSite、Path 和 HTTPS Secure 属性 | 通过 | | 登录回跳不能跳往外部网站 | 通过 | | 所有 Web POST 均经过 CSRF | 通过 | | Client API 不经过网页登录与浏览器 CSRF | 通过 | | 1366×768 初始化、登录及已登录导航布局 | 通过 | | Go 1.23.0 全量检查 | 通过 | ## 测试 - 执行的命令: ```powershell cd D:\chengma\cmautobuy\admin gofmt -l . go vet ./... go build ./... go test ./... -count=1 ``` - 结果:Go 版本为 `go1.23.0 windows/amd64`;全部通过,`gofmt -l .` 无输出。 - 浏览器验证:使用隔离的临时数据库,在 1366×768 完成 `/setup` 初始化、`/login` 登录并进入 `/shopee`;表单标签、密码框、提示、用户名和退出按钮均正常。 - **没验证到的部分**:没有在真实 HTTPS 服务上手工检查浏览器 Cookie,`Secure` 属性由带 TLS 请求的单元测试覆盖;没有触发真实采集或采购。 ## 相关提交 - `0a7db40` feat: 实现 Admin 首次初始化与网页登录 (#50)