BIZ-127 完整用户系统架构设计 v1.0
| 项 |
内容 |
| 版本 |
v1.0 |
| 作者 |
梁思筑(architect) |
| 日期 |
2026-09-04 |
| 关联卡片 |
BIZ-127(架构)→ BIZ-129(实施) |
| 父卡片 |
BIZ-109(P0 修复闭环) |
| 关联 PRD |
BIZ-111(产品 PRD) |
| 存储位置 |
docs/BIZ-127_完整用户系统架构_v1.0.md |
| 同步位置 |
思源知识库 /standards/完整用户系统架构 v1.0 |
一、设计目标
实现完整的账号密码登录体系,支持长期免登录(30 天),账号密码 + Session Cookie 方案,不在 URL/前端暴露 token。
二、数据模型
完整 SQL DDL 见 docs/auth-schema.sql(9.7KB)。
包含 5 张表:
- users —— 用户表(bcrypt 密码哈希、登录失败计数、锁定时间戳、多租户/角色预留)
- sessions —— 服务端会话(DB 存,非 JWT;存 session_hash、password_epoch 用于改密失效)
- password_reset_tokens —— 密码重置 token(一次性、1 小时过期、限速 3 次/小时)
- operation_logs —— 操作日志(90 天保留、多租户索引预留)
- auth_settings —— 全局鉴权配置(bcrypt cost、session 寿命、锁定参数)
关键决策
| 决策点 |
选择 |
理由 |
| Session 存储 |
DB 存 |
可控失效、改密立即踢人;JWT 不适合内网场景 |
| 重置 token 存储 |
DB 存 |
一次性、可控、可限速;JWT 自包含不可撤销 |
| 密码哈希 |
bcrypt cost=12 |
行业标准,登录耗时 ~250ms,安全/性能平衡 |
| 多用户扩展 |
数据层预留 + UI 不暴露 |
见下文"多用户扩展决策" |
三、鉴权中间件流程图
5 个鉴权端点
| 端点 |
方法 |
说明 |
/api/login |
POST |
账号密码 → 校验 → 创建 session → 设置 cookie |
/api/logout |
POST |
清 cookie → 撤销 session(revoked_at=now) |
/api/password-reset/request |
POST |
生成 token → 邮件/日志通知(内网暂用日志) |
/api/password-reset/confirm |
POST |
校验 token → 改密码 → 撤销该用户所有 session |
装饰器改造
四、Cookie 安全策略
| 项 |
值 |
决策依据 |
| 名称 |
lotto_session |
业务前缀,避免与其它服务冲突 |
| httpOnly |
true |
✅ 阻止 XSS 读取 cookie |
| secure |
true(生产) / false(内网 HTTP 调试) |
内网暂不强制 HTTPS,但配置项保留 |
| sameSite |
Lax |
✅ 防 CSRF;Strict 会破坏外链跳转登录 |
| path |
/ |
全站生效 |
| maxAge |
30 * 24 * 3600 秒(30 天) |
满足"长期免登录"诉求 |
| domain |
当前域(不设) |
内网单域,不跨子域 |
防 CSRF 决策
不单独引入 CSRF token,理由:
SameSite=Lax 已防 95% CSRF(POST 表单跨站不携带 cookie)
- 关键操作(删除、改密码)二次校验(要求输入当前密码或确认)
- 如未来扩展第三方嵌入或 iframe 调用,再加 CSRF token
Session 续期策略
- 用户每次活跃请求,若
expires_at - now < 24h,则续期 30 天
last_seen_at 用于清理过期 session
五、多用户扩展决策(4 个判断点)
| 判断点 |
是否预留 |
决策 |
1. 数据库 users.tenant_id / role 字段 |
✅ 预留 |
已建字段,索引就绪,单租户默认 1 |
2. API 路径 /api/admin/users/* |
❌ 不预留 |
过度设计;未来需要时再加,无需现在占坑 |
| 3. 前端「多用户切换」入口 |
❌ 不预留 |
UI 保持单用户登录,多用户场景届时再迭代 |
4. 操作日志按 tenant_id 分区 |
✅ 预留索引 |
已建 idx_oplog_tenant_time,分区待数据量>10万再分表 |
预留原则:数据库层 vs API/UI 层
- 数据层:必须预留(成本低、不影响当前 UI)
- API/UI 层:不预留(避免过度设计、未来按需添加)
六、兼容性矩阵
| 项 |
当前实现 |
方案 C 后 |
迁移路径 |
/api/status |
无鉴权 |
保持无鉴权(status 公开) |
无变更 |
/api/records |
Bearer 鉴权 |
Cookie 鉴权 + Bearer 备用 |
双轨运行 24h,前端切到 cookie 后撤 Bearer |
/api/history |
Bearer 鉴权 |
Cookie 鉴权 + Bearer 备用 |
同上 |
/api/generate |
Bearer 鉴权 |
Cookie 鉴权 + Bearer 备用 |
同上 |
/api/statistics |
Bearer 鉴权 |
Cookie 鉴权 + Bearer 备用 |
同上 |
/api/download/* |
Bearer 鉴权 |
Cookie 鉴权 + Bearer 备用 |
同上 |
| Bearer token |
LOTTO_API_TOKEN env 强制 |
保留 env(内部脚本用) |
不删除,作为内部服务通道 |
| Cookie |
无 |
lotto_session 30 天 |
新增 |
| 默认账号 |
无 |
lotto_admin + 临时密码 |
首次登录强制改密 |
双轨过渡策略:
- 上线 Cookie 鉴权后,前端自动改用 cookie
- Bearer 通道保留 24h 给内部脚本迁移
- 24h 后仅允许 Bearer 用于
/api/internal/*(如有)
- 监控
/api/records 等接口的鉴权失败日志,确认为 0 后撤 Bearer
七、性能 + 安全边界(5 项决策)
| 项 |
决策 |
理由 |
| 1. bcrypt cost=12 登录耗时 |
目标 < 500ms(实测 ~250ms) |
Ubuntu 22.04 + bcrypt cost=12 单次 ~250ms,远低于 500ms 上限 |
| 2. Session 失效机制(改密) |
改密码后该用户所有 session 立即失效 |
session 表 password_epoch 字段;登录时快照,改密后 password_changed_at 更新,session 自动失效 |
| 3. 找回密码 token 速率限制 |
每用户 3 次/小时 |
防爆破;超限返回 429 |
| 4. 登录失败锁定 |
5 次失败锁定 15 分钟 |
users.failed_attempts + locked_until;自动解锁 |
| 5. 操作日志保留周期 |
90 天 |
满足审计需求;月度归档到 operation_logs_archive_yyyyMM;>10万行/天时启动分区 |
八、验收 Checklist
九、对下游约束(PRD BIZ-111 + 实施 BIZ-129)
给 BIZ-111 PRD 的约束
- 登录页必须有:用户名、密码、"记住我"勾选(默认勾选=30天免登录)
- 找回密码流程:输入用户名 → 后台生成 token → 通过日志/邮件通知(内网暂用日志)
- 首次登录强制改密:检测
password_changed_at == created_at 时,强制跳改密页
- UI 不暴露多用户切换、注册入口(保持单账号)
给 BIZ-129 实施的约束
- 必须用 bcrypt cost=12,不要用 sha256/md5/pbkdf2
- session_id 必须 32 字节 URL-safe base64(
secrets.token_urlsafe(32))
- session_hash = sha256(session_id + server_secret),secret 存 env
- 不改 LOTTO_API_TOKEN 流程,保留 Bearer 作为内部通道
- /api/status 必须保持公开,不能误加鉴权
- BIZ-109 严格鉴权基线不能回退(不能因为 Cookie 引入新的 401 路径)
十、风险与待澄清
| 风险 |
影响 |
应对 |
| 首次部署 bcrypt 哈希生成失败 |
登录失败 |
BIZ-129 部署前在本地预生成哈希嵌入 init SQL |
| Cookie 30 天过长,安全边界争议 |
安全 |
auth_settings.session_max_age_sec 运行时可调 |
| 多用户预留字段被误用 |
数据污染 |
在 BIZ-129 代码层加 tenant_id == 1 断言 |
| 操作日志 90 天后未归档 |
磁盘膨胀 |
BIZ-129 实施时同时交付归档脚本 |
十一、变更历史
| 版本 |
日期 |
变更 |
作者 |
| v1.0 |
2026-09-04 |
初版(BIZ-127 架构交付) |
梁思筑 |