Files
wecom_it_smart_desk/docs/02-技术文档/技术方案-REQ-通用-006-预生产测试通道-v1.0.md
Simon c1d5dd584c [REQ-通用-006] 预生产测试通道:三端测试登录入口 + 文档链 + 部署脚本
- 三端 Login.vue(坐席/管理/H5)新增「测试账号登录」面板:探测 /api/dev/health 决定可见性,公网 403 自动隐藏,免企微扫码登录(token 写入对应 localStorage 键)
- 新增 REQ-通用-006 文档链五件套:PRD / 技术方案 / 任务说明书 / 测试用例 / 部署方案(product-doc-standard 规范)
- 版本迭代总览追加 v5.1(预生产测试通道)行
- 部署辅助脚本:nginx /api/dev/ 内网闸门注入、H5 版本化 v20260808→v20260811 升级

部署已落地预生产(10.90.5.110):公网 /api/dev/* 403、内网 200、三端登录页新 hash 在线。
2026-08-11 11:29:20 +08:00

163 lines
7.3 KiB
Markdown
Raw Permalink 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.
# 技术方案-REQ-通用-006-预生产测试通道
> **版本**: v1.0 | **日期**: 2026-08-11 | **状态**: [待评审]
> **作者**: 宋献(技术) | **审核**: —
> **REQ编号**: REQ-通用-006
> **关联PRD**: `../01-产品文档/00-产品规划/PRD-REQ-通用-006-预生产测试通道-v1.0.md`
> **关联测试**: `../03-测试文档/03-功能测试用例/TC-REQ-通用-006-预生产测试通道.md`
> **需了解的现有代码**:
> - 后端: `src/backend/app/api/dev_auth.py`Mock 登录,已存在)
> - 后端: `src/backend/app/main.py``_is_dev_mode()` + dev 路由挂载)
> - 坐席前端: `src/frontend-agent/src/views/Login.vue`、`src/frontend-agent/src/api/auth.ts`、`src/frontend-agent/src/stores/agent.ts`
> - 管理前端: `src/frontend-admin/src/views/Login.vue`
> - H5前端: `src/frontend-h5/src/`(登录与 token 存储)
---
## 1. 现状分析
### 1.1 认证架构现状
- 三端统一企微扫码/OAuth`/api/auth/qrcode` + `/api/auth/oauth2/*`),无账号密码入口
- 后端 `/api/agents/login` 已废弃(DEPRECATED),且依赖企微通讯录验证 user_id,不满足"免企微"测试诉求
- **既有测试基建**`/api/dev/login``dev_auth.py`)在 `DEV_MODE=true` 时挂载,走真实 TokenService 流程、自动同步 employees 表、带角色预设(user/agent/admin/supervisor/security/多角色);本地 `src/backend/.env``DEV_MODE=true`,后端测试 conftest 亦 mock 企微
### 1.2 前端 token 存储机制(已核实)
| 端 | 存储键 | 用途 |
|----|--------|------|
| 坐席 | `localStorage.TOKEN_KEY`store: agent.ts | 请求拦截器自动附加 Bearer |
| H5 | `localStorage.h5_token` | 同上 |
| 管理 | 与坐席同构(login 后写入 store | 同上 |
→ 测试登录仅需把 `/api/dev/login` 返回的 token 写入对应键,即可进入业务态。
---
## 2. 总体设计
```
公网用户 ──► WAF ──► nginx ──┬── /itdesk|/itagent|/itadmin/ 静态页(登录页,含测试入口按钮)
├── /api/auth/* 企微扫码主登录(不变)
├── /api/dev/* ◄── nginx 闸门:allow 内网网段;deny all
│ │
│ ▼
└── backend (DEV_MODE=true) ── /api/dev/login → TokenService → Redis token
```
**三层防线**
1. **nginx 闸门**(主闸门):`location /api/dev/ { allow 内网; deny all; }` —— 公网直接 403
2. **后端二次校验**`dev_auth.py` 各端点内部 `_dev_mode_enabled()` 再校验(`DEV_MODE=true` 才放行)
3. **前端可见性**:测试登录入口仅在内网判定(hostname 非公网域名 / 内网网段探测)时渲染
---
## 3. 详细设计
### 3.1 后端配置(零代码改动)
预生产 `docker-compose.yml``/opt/wecom-it-desk/`backend 服务 `environment:` 追加:
```yaml
- DEV_MODE=true
```
重启后端容器(`docker compose up -d backend` 或 recreate)后:
- `/api/dev/login``/api/dev/users``/api/dev/health` 挂载
- 启动日志出现 `🧪 DEV_MODE 已启用 - Mock OAuth 端点已挂载`
**生产安全隔离**:新生产 compose **不得**注入 `DEV_MODE``.dockerignore` 已排除 `.env`(防止本地 DEV_MODE 进镜像),双保险。
### 3.2 nginx 闸门(预生产主控)
在线上 `/opt/wecom-it-desk/nginx/nginx.conf` 生产 server 块 `location /api/` **之前**插入:
```nginx
location /api/dev/ {
allow 10.0.0.0/8;
allow 172.16.0.0/12;
allow 192.168.0.0/16;
deny all;
proxy_pass http://backend_api/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
```
> 注意:`location /api/dev/` 前缀比 `location /api/` 更长,nginx 最长前缀优先匹配,无需改动既有 `/api/` 块。
### 3.3 前端三端测试登录入口
**判定内网**(复用常量,与 nginx 闸门网段同源):
```ts
const TEST_NETS = ['10.', '172.16.', '172.17.', '172.18.', '172.19.', '172.20.', '172.21.', '172.22.', '172.23.', '172.24.', '172.25.', '172.26.', '172.27.', '172.28.', '172.29.', '172.30.', '172.31.', '192.168.']
function isIntranet(): boolean {
// 通过 /api/dev/health 探测:内网 200 → 显示测试入口;公网 403 → 隐藏
}
```
**推荐实现**:登录页 onMounted 时静默探测 `GET /api/dev/health`
- HTTP 200 → 渲染「测试账号登录」面板(角色下拉:user/agent/admin,对应 `PRESET_DEV_USERS`
- 403/网络错误 → 不渲染(公网用户不可见)
**登录动作**(坐席端示例,管理/H5 同构):
```ts
const data = await apiClient.get('/dev/login', { params: { userid: 'dev-agent-001', name: '李四(IT坐席)', role: 'agent' } })
localStorage.setItem(TOKEN_KEY, data.data.token) // 与企微扫码登录写入同一键
// 刷新/跳转业务页,拦截器自动携带 token
```
> 兜底:若 `health` 探测失败(如中间层拦截),可降级为"仅 hostname 非 `itsupport.servyou.com.cn` 时显示"——测试环境通常走内网 IP/测试域名。
### 3.4 token 生命周期
- `/api/dev/login` 返回的 token 与企微登录同源(TokenServiceTTL 8h),Redis 可校验、登出接口可吊销
- 测试账号 userid 前缀 `dev-*`,与真实账号隔离,不污染统计
---
## 4. 关键决策与取舍
| 决策点 | 选择 | 理由 |
|--------|------|------|
| 测试通道形态 | 启用既有 DEV_MODE + `/api/dev/*` | 零后端开发;接口已含二次校验;预设用户即测即用 |
| 闸门层级 | nginx IP 白名单(主)+ 后端校验(次) | nginx 层拦截最前置、可独立回滚;后端校验防配置遗漏 |
| 公网可见性 | 前端探测 `/api/dev/health` 决定是否显示测试入口 | 公网 403 → 入口自动隐藏,双保险 |
| 不做的事 | 不新增生产密码登录、不改企微主流程 | 安全红线,见 PRD § 2.3 |
---
## 5. 验证方式
| # | 验证项 | 方法 | 预期 |
|---|--------|------|------|
| V-1 | 内网 dev/login 可用 | 内网 curl `GET /api/dev/login?userid=dev-agent-001&role=agent` | 200 + token |
| V-2 | 公网 dev 接口 403 | 公网 curl `GET /api/dev/health` | 403 |
| V-3 | 业务接口未误伤 | 公网 curl `GET /api/health` | 200 |
| V-4 | 前端测试入口 | 内网打开三端登录页 | 显示测试账号面板,一键登录进业务页 |
| V-5 | 主登录回归 | 企微扫码/OAuth 流程 | 不受影响 |
| V-6 | token 真实有效 | Redis `GET user:token:*` | 存在且 TTL 正常 |
---
## 6. 风险与回滚
| 风险 | 缓解/回滚 |
|------|----------|
| 闸门配置语法错误 | `nginx -t` 先行校验;失败即回滚 conf(备份已建) |
| 公网仍可访问 dev 接口 | 立即回滚:删除 `location /api/dev/` 块 + 移除 `DEV_MODE` → 重启后端 |
| 前端构建问题 | 三端 dist 备份,回滚到上一版本 dist |
| 误伤 `/api/` 业务 | 闸门仅精确前缀 `/api/dev/`,最长前缀匹配不影响其他;验证 V-3 |
---
## 7. 变更记录
| 日期 | 版本 | 变更内容 | 变更人 | 变更原因 |
|------|------|----------|--------|----------|
| 2026-08-11 | v1.0 | 初版 | 宋献 | 预生产测试通道技术方案 |