文档更新

This commit is contained in:
Shen Wei
2026-05-02 11:35:20 +08:00
parent 464c5fce51
commit ca33cc141f
21 changed files with 5906 additions and 2908 deletions

View File

@@ -2,22 +2,23 @@
# Fonrey 登录管理技术方案
**版本**: 4.0
**版本**: 4.1
**项目**: Fonrey 房产经纪管理系统
**技术栈**: Django 4.x + HTMX + Alpine.js + PostgreSQL 16 + Redis + Celery
**关联 PRD**: `PRD/登录管理/用户登录管理模块PRD.md`v2.0
**关联 PRD**: `PRD/登录管理/用户登录管理模块PRD.md`v3.0
**关联数据模型**: `DATA_MODEL/DATA_MODEL_LOGIN.md`(本方案不重复 DDL
**关联契约规范**: `TECH_STACK/API_CONTRACT.md`(全局 API 契约权威)
**关联测试规范**: `TECH_STACK/测试规范.md``TEST_CASES/TEST_CASES_LOGIN_MODULE.md`
**最后更新**: 2026-04-30
**最后更新**: 2026-05-02
---
## 变更历史
| 日期 | 变更人 | 变更内容 |
|---|---|---|
| 2026-04-30 | Atlas | 补充变更历史章节(文档治理) |
| 日期 | 变更人 | 变更内容 |
| ---------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 2026-04-30 | Atlas | 补充"变更历史"章节(文档治理) |
| 2026-05-02 | Sisyphus | 按 `ADR-20260502-003` 承接从 PRD v3.0 迁出的实现细节①§5.3 新增 Tenant Verify 请求/响应 JSON Schema②§5.3 新增预留 Wechat 端点 `GET /api/auth/wechat/qrcode/``POST /api/auth/wechat/callback/`仅占位MVP 不开放);③新增 §十三 Electron 客户端约定Tenant Code 存储/Session/登录页加载/多标签页/登出/窗口关闭/强制更新);④§六 关键流程约束补全密码错误锁定阈值、滑块容差、找回密码错误次数等数值口径,统一以本文件为准 |
## 一、文档定位与边界
@@ -96,26 +97,26 @@
---
## 五、端点清单(对齐 PRD
## 五、端点清单
### 5.1 页面路由SSR
| 路径 | 方法 | 鉴权 | 说明 |
|---|---|---|---|
| `/auth/tenant/identify/` | GET | 否 | Tenant 识别页 |
| `/auth/login/` | GET | 否 | 登录页(密码登录/验证码登录 Tab |
| `/auth/password/forgot/` | GET | 否 | 找回密码三步页 |
| `/auth/password/change-initial/` | GET | 是 | 首次登录强制改密页 |
| 路径 | 方法 | 鉴权 | 说明 |
| -------------------------------- | --- | --- | ------------------- |
| `/auth/tenant/identify/` | GET | 否 | Tenant 识别页 |
| `/auth/login/` | GET | 否 | 登录页(密码登录/验证码登录 Tab |
| `/auth/password/forgot/` | GET | 否 | 找回密码三步页 |
| `/auth/password/change-initial/` | GET | 是 | 首次登录强制改密页 |
> 说明:`/auth/wechat/*` 仅预留,不在 MVP 开放。
### 5.2 HTMX 片段端点
| 路径 | 方法 | 用途 | 返回 |
|---|---|---|---|
| `/auth/fragments/captcha/` | GET | 刷新滑块区块 | HTML 片段 |
| `/auth/fragments/login-form/` | GET | 登录 Tab 内容局刷 | HTML 片段 |
| `/auth/fragments/forgot-step/` | GET | 找回密码步骤局刷 | HTML 片段 |
| 路径 | 方法 | 用途 | 返回 |
| ------------------------------ | --- | ----------- | ------- |
| `/auth/fragments/captcha/` | GET | 刷新滑块区块 | HTML 片段 |
| `/auth/fragments/login-form/` | GET | 登录 Tab 内容局刷 | HTML 片段 |
| `/auth/fragments/forgot-step/` | GET | 找回密码步骤局刷 | HTML 片段 |
### 5.3 JSON APIMVP
@@ -132,6 +133,46 @@
| `/api/auth/password/change-initial/` | POST | 首次登录强制改密提交 |
| `/api/auth/logout/` | POST | 登出销毁会话 |
#### 5.3.1 Tenant Verify 请求/响应 Schema
请求体:
```json
{ "tenant_code": "202500010001" }
```
成功响应HTTP 200
```json
{
"valid": true,
"tenant_name": "XX房产经纪有限公司",
"tenant_logo_url": "https://cdn.fonrey.com/tenants/xxx/logo.png",
"login_url": "https://xxx.fonrey.com/auth/login/"
}
```
失败响应HTTP 200业务态失败
```json
{
"valid": false,
"error_code": "AUTH_TENANT_NOT_FOUND",
"message": "识别码无效"
}
```
限流超限响应HTTP 429遵循 `API_CONTRACT.md` 统一错误格式,`code = AUTH_TENANT_RATE_LIMITED`
### 5.4 预留端点MVP 不开放)
| 端点 | 方法 | 状态 | 说明 |
|---|---|---|---|
| `/api/auth/wechat/qrcode/` | GET | 仅占位 | 微信扫码登录二维码获取v2 实现) |
| `/api/auth/wechat/callback/` | POST | 仅占位 | 微信扫码回调换取系统 Tokenv2 实现) |
> MVP 内 URLConf 中**不注册**这两个路由,登录页 UI 入口以禁用态展示v2 启用时再按本表落地路由与视图。
---
## 六、关键流程约束
@@ -274,3 +315,42 @@
- 数据结构调整:同步 `DATA_MODEL_LOGIN.md`
- 测试用例新增/变更:同步 `TEST_CASES/TEST_CASE_REGISTRY.md` 与登录用例文档
- API 契约调整:同步 `TECH_STACK/API_CONTRACT.md`
---
## 十三、Electron 客户端约定(实现口径)
> 承接自原 PRD §5.7(按 `ADR-20260502-003` 迁入本文件)。本节为 Electron 渲染层与主进程在登录链路上的实现规约,开发时必须严格遵循。
### 13.1 存储与会话
| 约定项 | 实现规格 |
|---|---|
| Tenant Code 存储 | `electron-store``app.getPath('userData')` 下的配置文件,**必须 AES 加密**,禁止明文落盘 |
| Session Token 存储 | 内存(主进程 `global` 变量)+ Chromium 管理的 `session` Cookie`HttpOnly` + `Secure` + `SameSite=Strict`**禁止写入磁盘明文文件** |
| 多标签页 | 同一 `BrowserWindow` 内,所有页面共享同一 `session.defaultSession`,复用同一 Session Cookie |
| 窗口关闭 | Session 保留(不自动登出);下次启动客户端时,若 Cookie 未过期且 `/api/auth/whoami/` 校验通过,直接进入系统 |
### 13.2 登录页加载流程
1. 主进程读取本地缓存的 `tenant_code`
- 不存在 → `BrowserWindow.loadURL('app://tenant-identify')`(本地静态页或专用 Tenant 识别 URL
- 存在 → 调用 `POST /api/auth/tenant/verify/` 复核(防止租户被禁用 / 改名)
- 成功 → 构建 `https://{tenant_slug}.fonrey.com/auth/login/`,通过 `BrowserWindow.loadURL()` 加载
- 失败 → 清除本地 `tenant_code` 缓存 → 跳回 Tenant 识别页
2. 切换公司:用户在登录页点击「切换公司」 → 主进程清缓存 → 关闭当前 `BrowserWindow` → 重新走步骤 1。
### 13.3 登出与强制更新
| 场景 | 客户端动作 |
|---|---|
| 用户登出 | 调用 `POST /api/auth/logout/` → 清除 Chromium Session Cookie`session.defaultSession.clearStorageData({ storages: ['cookies'] })`)→ 跳转登录页 |
| 服务端 Session 过期401 | 渲染层捕获 401 → 主进程清 Cookie → 跳转登录页并提示"登录已过期,请重新登录" |
| 客户端版本低于 `min_required_version` | 加载登录页前先展示"请更新客户端"模态,阻断登录流程;联动 `平台管理后台技术方案.md` 客户端发布章节 |
### 13.4 安全约束(与 AGENTS.md §5 对齐)
- 渲染进程必须 `nodeIntegration: false``contextIsolation: true``sandbox: true`
- 渲染层禁止内嵌业务逻辑或本地数据库(壳应用原则);
- 主进程与渲染层之间通过 `contextBridge` 暴露的最小白名单 IPC 接口通信;
- 仅允许加载 `https://*.fonrey.com``app://` 协议,其他 URL 在 `will-navigate` 中拦截。