c1d5dd584c
- 三端 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 在线。
163 lines
7.3 KiB
Markdown
163 lines
7.3 KiB
Markdown
# 技术方案-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 与企微登录同源(TokenService,TTL 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 | 初版 | 宋献 | 预生产测试通道技术方案 |
|