8.1 KiB
8.1 KiB
For AI assistants: Read this entire file before writing any code. All decisions here are final. Do not suggest alternatives unless asked.
Fonrey 登录管理技术方案
版本: 3.1
项目: Fonrey 房产经纪管理系统
技术栈: Django 4.x + HTMX + Alpine.js + PostgreSQL 16 + Redis + Celery
关联 PRD: PRD/登录管理/用户登录管理模块PRD.md
关联数据模型: DATA_MODEL/DATA_MODEL_LOGIN.md(本方案不重复 DDL)
关联契约规范: TECH_STACK/API_CONTRACT.md(全局 API 契约权威)
最后更新: 2026-04-27
一、文档定位与边界
本文件仅定义登录模块的:
- 模块边界与服务职责
- API 端点设计(页面 / HTMX / JSON)
- 登录安全策略(验证码、锁定、会话、找回)
- 缓存与异步任务策略
- 错误码与测试映射
不在本文件展开表字段、索引、DDL。数据结构以
DATA_MODEL_LOGIN.md为唯一权威。
二、范围定义(以 P0 为准)
2.1 P0 必须覆盖
- Tenant ID 校验(Public Schema)
- 用户名 + 密码登录(Tenant Schema)
- 验证码挑战与一次性 pass token
- 连续失败锁定与解锁机制
- 找回用户名 / 重置密码
- 首次登录强制改密
- 安全登出与会话销毁
2.2 预留(非本期强制)
- MFA(OTP / 短信)
- 企业 SSO(OAuth2 / SAML)
- 设备指纹与风险评分
三、模块架构边界
3.1 模块职责(apps/account)
- 登录认证入口与 Session 建立
- 密码策略、锁定策略、登录防刷策略执行
- 找回流程与一次性重置令牌管理
- 登录/登出/失败审计事件写入
3.2 多租户分层职责
| 层级 | Schema | 职责 |
|---|---|---|
| Tenant ID 校验 | Public | 校验租户标识、域名映射、租户状态 |
| 登录认证 | Tenant | 账号鉴权、失败计数、会话建立 |
| 密码找回 | Tenant | 身份确认、令牌签发与核销 |
3.3 外部依赖
| 依赖模块 | 用途 |
|---|---|
apps/org |
员工状态联动(离职/冻结禁止登录) |
core/encryption.py |
手机号等敏感信息加密与脱敏 |
core/cache.py |
验证码票据、失败计数、频控缓存 |
Celery |
找回消息异步发送、安全日报任务 |
四、API 设计原则
- 登录链路固定三段:Tenant 校验 → 验证码 → 账号认证。
- 最小暴露原则:账号不存在与密码错误统一返回。
- 认证状态以数据库为准,Redis 仅做加速与频控。
- 安全相关写操作后立即失效缓存,不依赖 TTL。
- HTMX 返回片段,JSON 返回结构化错误体。
五、端点清单(核心)
5.1 页面路由(SSR)
| 路径 | 方法 | 鉴权 | 说明 |
|---|---|---|---|
/account/tenant/verify/ |
GET | 否 | 首次租户识别页 |
/account/login/ |
GET | 否 | 登录页 |
/account/change-password/ |
GET | 是 | 首登强制改密页 |
/account/recover-username/ |
GET | 否 | 找回用户名页 |
/account/recover-password/ |
GET | 否 | 找回密码页 |
5.2 HTMX 片段端点
| 路径 | 方法 | 用途 | 返回 |
|---|---|---|---|
/account/fragments/login-form/ |
GET | 登录表单局刷 | HTML 片段 |
/account/fragments/captcha/ |
GET | 验证码区块刷新 | HTML 片段 |
/account/fragments/recover-step/ |
GET | 找回步骤局刷 | HTML 片段 |
5.3 JSON API(P0)
| 端点 | 方法 | 说明 |
|---|---|---|
/api/account/tenant/verify/ |
POST | 校验 tenant_id 与可用性 |
/api/account/captcha/generate/ |
POST | 生成验证码 challenge |
/api/account/captcha/verify/ |
POST | 校验 challenge 并签发 pass token |
/api/account/login/ |
POST | 登录并建立 session |
/api/account/logout/ |
POST | 登出并销毁 session |
/api/account/password/change/ |
POST | 登录态改密 |
/api/account/username/recover/ |
POST | 找回用户名 |
/api/account/password/recover/request/ |
POST | 申请重置密码令牌 |
/api/account/password/recover/reset/ |
POST | 使用令牌重置密码 |
六、关键 API 规范(请求/响应)
6.1 登录
POST /api/account/login/
{
"tenant_id": "fonrey-sh",
"username": "agent_001",
"password": "******",
"captcha_pass_token": "token"
}
成功 200:
{
"message": "登录成功",
"redirect_url": "/home/"
}
失败码:ACCOUNT_LOGIN_INVALID_CREDENTIAL / ACCOUNT_LOCKED / ACCOUNT_CAPTCHA_INVALID
6.2 申请重置密码
POST /api/account/password/recover/request/
{
"tenant_id": "fonrey-sh",
"username": "agent_001",
"contact": "138****0000"
}
规则:
- 频率限制(建议 5 次/小时)
- 统一返回文案,避免枚举账号存在性
七、HTMX 交互约定
7.1 Header 约定
- 请求头:
HX-Request: true - 成功触发:
HX-Trigger: {"toast":{"level":"success","message":"操作成功"}} - 失败触发:
HX-Trigger: {"toast":{"level":"error","message":"操作失败"}} - 登录成功:
HX-Redirect: /home/
7.2 模板分片命名
templates/account/fragments/login_form.htmltemplates/account/fragments/captcha_panel.htmltemplates/account/fragments/recover_step.html
八、权限与数据范围
8.1 访问控制
- 匿名可访问:租户校验、登录、找回相关端点
- 登录后访问:改密、登出
- 首登未改密用户仅允许访问改密页面
8.2 审计字段要求
登录与找回相关操作至少记录:
- tenant_schema
- username(或脱敏标识)
- ip / user_agent
- result_code
- created_at
九、异步任务与缓存策略
9.1 Celery 任务
| 任务 | 触发时机 | 说明 |
|---|---|---|
account_send_recover_message_task |
找回请求成功后 | 异步发送邮件/短信 |
account_security_digest_task |
定时任务 | 汇总锁定、失败、异常登录统计 |
9.2 Redis Key 规范
| Key | TTL | 说明 |
|---|---|---|
{schema}:account:captcha:{challenge_id} |
180s | 验证码挑战态 |
{schema}:account:captcha:pass:{token} |
180s | 验证通过一次性票据 |
{schema}:account:login_fail:{username} |
1800s | 登录失败计数 |
{schema}:account:recover:rate:{username} |
3600s | 找回频控 |
十、性能与可靠性约束
- 登录链路接口目标:
p95 < 300ms(不含外部消息发送) - 找回请求接口目标:
p95 < 400ms(消息发送异步化) - 缓存故障时系统应降级到 DB 校验,但保留频控硬兜底
- 验证码组件不可用时,应返回明确错误并禁止跳过登录防护
十一、安全与合规
- 密码仅允许 Django 安全哈希(PBKDF2 / Argon2)。
- 连续失败 N 次锁定(建议 5 次,30 分钟)。
- 重置令牌一次性使用,过期失效,不可复用。
- 登出必须销毁会话,旧页面刷新需重定向登录。
- 敏感字段仅脱敏返回,禁止明文日志输出。
十二、错误码建议
| code | HTTP | 场景 |
|---|---|---|
ACCOUNT_TENANT_INVALID |
400 | tenant 无效或停用 |
ACCOUNT_CAPTCHA_INVALID |
400 | 验证码失败/过期 |
ACCOUNT_LOGIN_INVALID_CREDENTIAL |
401 | 账号或密码错误 |
ACCOUNT_LOCKED |
423 | 账号锁定中 |
ACCOUNT_PASSWORD_WEAK |
400 | 新密码不满足复杂度 |
ACCOUNT_RESET_TOKEN_INVALID |
400 | 重置令牌无效/已使用 |
十三、测试映射(P0)
| 场景 | 最低覆盖 |
|---|---|
| Tenant 校验 | 有效/无效/停用租户 |
| 登录链路 | 验证码通过、失败锁定、解锁后登录 |
| 找回流程 | 频控、令牌一次性、过期处理 |
| 首登改密 | 未改密不可进入业务页 |
| 登出 | 会话销毁、回退重定向 |
测试文件:tests/integration/account/test_us_account.py
十四、落地顺序建议
- 先实现 tenant 校验 + 登录主链路
- 再接验证码 + 失败锁定
- 再实现找回用户名/密码
- 最后补安全摘要任务与审计报表
十五、文档同步规则
- 登录数据结构调整:同步
DATA_MODEL_LOGIN.md - 安全策略或门禁调整:同步
权限管理系统技术方案.md - API 变更:同步本文件与登录 PRD 验收条目