Files
nexus/Project/fonrey/TECH_STACK/登录管理技术方案.md
2026-04-28 07:38:30 +08:00

283 lines
8.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
> **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
---
## 一、文档定位与边界
本文件仅定义登录模块的:
1. 模块边界与服务职责
2. API 端点设计(页面 / HTMX / JSON
3. 登录安全策略(验证码、锁定、会话、找回)
4. 缓存与异步任务策略
5. 错误码与测试映射
> 不在本文件展开表字段、索引、DDL。数据结构以 `DATA_MODEL_LOGIN.md` 为唯一权威。
---
## 二、范围定义(以 P0 为准)
### 2.1 P0 必须覆盖
- Tenant ID 校验Public Schema
- 用户名 + 密码登录Tenant Schema
- 验证码挑战与一次性 pass token
- 连续失败锁定与解锁机制
- 找回用户名 / 重置密码
- 首次登录强制改密
- 安全登出与会话销毁
### 2.2 预留(非本期强制)
- MFAOTP / 短信)
- 企业 SSOOAuth2 / 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 设计原则
1. 登录链路固定三段Tenant 校验 → 验证码 → 账号认证。
2. 最小暴露原则:账号不存在与密码错误统一返回。
3. 认证状态以数据库为准Redis 仅做加速与频控。
4. 安全相关写操作后立即失效缓存,不依赖 TTL。
5. 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 APIP0
| 端点 | 方法 | 说明 |
|---|---|---|
| `/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/`
```json
{
"tenant_id": "fonrey-sh",
"username": "agent_001",
"password": "******",
"captcha_pass_token": "token"
}
```
成功 `200`
```json
{
"message": "登录成功",
"redirect_url": "/home/"
}
```
失败码:`ACCOUNT_LOGIN_INVALID_CREDENTIAL` / `ACCOUNT_LOCKED` / `ACCOUNT_CAPTCHA_INVALID`
## 6.2 申请重置密码
`POST /api/account/password/recover/request/`
```json
{
"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.html`
- `templates/account/fragments/captcha_panel.html`
- `templates/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 校验,但保留频控硬兜底
- 验证码组件不可用时,应返回明确错误并禁止跳过登录防护
---
## 十一、安全与合规
1. 密码仅允许 Django 安全哈希PBKDF2 / Argon2
2. 连续失败 N 次锁定(建议 5 次30 分钟)。
3. 重置令牌一次性使用,过期失效,不可复用。
4. 登出必须销毁会话,旧页面刷新需重定向登录。
5. 敏感字段仅脱敏返回,禁止明文日志输出。
---
## 十二、错误码建议
| 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`
---
## 十四、落地顺序建议
1. 先实现 tenant 校验 + 登录主链路
2. 再接验证码 + 失败锁定
3. 再实现找回用户名/密码
4. 最后补安全摘要任务与审计报表
---
## 十五、文档同步规则
- 登录数据结构调整:同步 `DATA_MODEL_LOGIN.md`
- 安全策略或门禁调整:同步 `权限管理系统技术方案.md`
- API 变更:同步本文件与登录 PRD 验收条目