Files
wecom_it_smart_desk/docs/02-技术文档/技术架构/技术方案-REQ-通用-004-敏感词检测-v1.1.1.md
T
Simon facc04aa65 chore: docs 结构整改 + compose 双目录对齐(合并重建提交)
本提交为 .git 对象库损坏后的重建提交,内容等价于原先三个本地提交
(5e2fd4c2 / 57a53c98 / 5d7e1873)的累积结果,未做任何额外改动。

一、docs 结构整改(整改 #14)
根因:重构时新结构为 untracked 文件,执行 git stash(未带 -u)未纳入,
随后 git reset 拉回 HEAD 旧 tracked 树,导致旧树复活、新旧两棵目录
树并存于 docs/,共 791 文件、双分类体系冲突。

修复动作:
- b2 同名异主题文件改名迁移保全 9 个
- C 类 39 个孤立文件按主题正确归类
- A/B1 类 222 个重复文件删除(新结构已有内容副本)
- 9 个旧独有空目录删除
- 270 处内部引用按 verified 映射改写
- 整改记录 #14 登记于 04-运维文档/部署运维

结果:docs 791 → 569 文件,顶层仅规范 8 类 + 治理文件,单树恢复。
残留:约 20 处指向从未存在文件的陈旧死链,归入独立文档卫生任务。

二、compose 双目录对齐(消除踩坑 A)
- docker-compose.yml:nginx 前端挂载全部由根目录 frontend-*/dist
  改为 src/frontend-*/dist(h5 / agent / admin / terminal)
- docker-compose.dev.yml:dev 服务 build context 与卷同步改 src/
- 效果:本地 docker compose up 不再把根目录 stale dist 挂回,
  与线上一致,分叉隐患消除(已 docker compose config 校验通过)

防复发铁律:
- 重构须提交;仓库修复须 git stash -u 或先 commit
- 新结构须 git add 并提交,避免再次 untracked 复活
- H5 改动只动 src/frontend-h5/,禁改根目录遗留 frontend-*/
2026-08-07 22:31:32 +08:00

12 KiB
Raw Blame History

技术方案 - REQ-通用-004 敏感词检测 v1.1.1(鉴权安全补漏)

版本: v1.1.1v1.1 的安全补丁 / PATCH 级别) 日期: 2026-08-05 REQ编号: REQ-通用-004 状态: [待评审] → 待部署 作者: 宋献 / Duckula 关联PRD: docs/01-产品文档/00-产品规划/PRD-REQ-通用-004-敏感词检测-v1.1.1.md 关联缺陷单: docs/03-测试文档/05-缺陷单/BUG-通用-004-敏感词API无鉴权-001.md 关联任务说明书: docs/07-项目管理/任务说明书/任务说明书-REQ-通用-004-敏感词检测-v1.1.1.md 关联整改记录: docs/04-运维文档/部署运维/00-文档规范化整改记录.md#5 整改) 前置版本: 技术方案-REQ-通用-004-敏感词检测-v1.0.archive.md


目录

  1. 设计概述
  2. 根因定位
  3. 修复方案
  4. 代码变更清单
  5. 测试策略
  6. 部署与回滚
  7. 风险与豁免
  8. 关联文档
  9. 变更日志

1. 设计概述

1.1 背景

v1.02026-07-28)已规定所有 admin 命名空间下的端点需要 admin 角色;v1.12026-07-28)落地了 13 个 admin 端点(sensitive_words / privacy_patterns / moderation_logs / moderation_config),但实施时 src/backend/app/api/admin/sensitive_words.pyAPIRouter 创建时未挂 dependencies=[Depends(require_admin)]13 端点全部无鉴权。

v1.1.1 作为 PATCH 级别的安全补漏,仅做鉴权修复,不改任何业务逻辑、API 契约、数据库 schema。

1.2 设计目标

目标 描述
G1 一行全覆盖 修改 APIRouter 配置 + 一行 import13 端点同时获得 require_admin 依赖
G2 与现有模式一致 复用 app/api/admin_api.py:50 已定义的 require_admin 函数(不重复实现)
G3 行为对齐 admin_api.py 已加鉴权的同类端点行为完全一致:非 admin 返回 403 + AppException(1004, "无管理权限")
G4 零业务影响 admin 用户的 13 端点调用全部仍返回 200,业务流程不受影响
G5 与 v1.2 解耦 不动 AI 工作流 / Dify 集成 / service 层逻辑;可独立部署

1.3 不做

  • 不重构 service 层(SensitiveWordService
  • 不引入新依赖
  • 不修改任何端点的请求/响应 schema
  • 不修改数据库 schema
  • 不加 operator_id 审计字段(列入 v1.1.2 或 v1.2
  • 不加正则复杂度限制(列入 v1.1.2)
  • 不影响 v1.2 AI 化草案

2. 根因定位

2.1 三层根因

2.1.1 实现层(直接原因)

sensitive_words.py:44

# ❌ 当前实现(v1.1 落地时漏写)
router = APIRouter(prefix="/admin", tags=["敏感词管理(v1.1"])

应写为:

# ✅ v1.1.1 修复后
from app.api.admin_api import require_admin  # 第 1 处变更:顶部 imports

router = APIRouter(
    prefix="/admin",
    tags=["敏感词管理(v1.1"],
    dependencies=[Depends(require_admin)],  # 第 2 处变更:router 配置
)

2.1.2 规范层(间接原因)

技术方案 v1.0 §6.3 "v1.1 计划路由层" 表格中 11 个端点已明确列出"权限:admin"列

接口 方法 说明 权限
/api/admin/sensitive-words GET 列表查询 admin
/api/admin/sensitive-words POST 添加 admin
... ... ... admin
/api/admin/moderation-logs GET 审计日志查询 admin
/api/admin/moderation-stats GET 命中统计 admin

但 v1.1 实施时未对照此规范逐项实现。

2.1.3 流程层(系统原因)

任务说明书 v1.1 §5"输出成果要求"未列"鉴权维度验收"。TC-通用-004 31 条用例全在功能维度,无安全维度。

2.2 同类对照(不应发生但确实发生了)

文件 鉴权声明 端点数
admin_api.py 每端点 Depends(require_admin) 30+
admin_roles.py 已加 5
admin_users.py 已加 8
welcome.py 已加 3
quiz_admin.py 已加 5
troubleshooting_templates.py 已加 4
admin/sensitive_words.py 0 13

2.3 鉴权依赖来源

app/api/admin_api.py:50-66

async def require_admin(
    agent: Agent = Depends(get_current_agent),
) -> Agent:
    """管理后台权限校验:仅 role='admin' 可访问。"""
    if agent.role != "admin":
        raise AppException(1004, "无管理权限")
    return agent

可直接复用,不重复实现


3. 修复方案

3.1 修改点(共 2 处)

3.1.1 顶部 importsL33-41 后追加)

from app.api.admin_api import require_admin  # v1.1.1 鉴权补漏

3.1.2 APIRouter 配置(L44 替换)

router = APIRouter(
    prefix="/admin",
    tags=["敏感词管理(v1.1"],
    dependencies=[Depends(require_admin)],  # v1.1.1 鉴权补漏
)

3.2 行为变化

调用方 v1.1 行为 v1.1.1 行为
无 Authorization 200 OK(裸奔) 401 Unauthorized
普通坐席 token 200 OK(裸奔) 403 + code:1004 无管理权限
管理员 token 200 OK 200 OK(不变)
重载/正则测试等写操作 任意 token 可触发 仅 admin 可触发

3.3 鉴权链路(修复后)

HTTP Request
  │
  ▼
[1] Depends(require_admin)
  │
  ├──▶ Depends(get_current_agent) ─── 解析 JWT ───▶ 401 (token 无效)
  │
  ▼
[2] if agent.role != "admin": raise AppException(1004, "无管理权限")
  │
  ▼
[3] 进入 sensitive_words endpoint handler
  │
  ▼
[4] handler 返回 success_response(...)

4. 代码变更清单

文件 变更类型 行号 内容
src/backend/app/api/admin/sensitive_words.py 修改 顶部 imports 新增 from app.api.admin_api import require_admin
src/backend/app/api/admin/sensitive_words.py 修改 L44 APIRouter 加 dependencies=[Depends(require_admin)]
src/backend/tests/test_sensitive_words_auth.py 新增 - 6 条鉴权测试用例

无 DB 迁移、无 frontend 改动、无 nginx 改动、无 docker-compose 改动。


5. 测试策略

5.1 新增自动化测试

src/backend/tests/test_sensitive_words_auth.py

用例 输入 预期
test_no_token_returns_401 无 Authorization 401
test_invalid_token_returns_401 Bearer "invalid" 401
test_agent_role_returns_403 普通坐席 token 403 + code:1004
test_admin_role_returns_200_list admin GET /sensitive-words 200
test_admin_role_returns_200_reload admin POST /sensitive-words/reload 200
test_admin_role_returns_200_pattern_test admin POST /privacy-patterns/{id}/test 200

5.2 容器内端到端验证

deploy-troubleshoot 铁律:宣布修复前必须端到端验证

# 1) 进入容器 grep 验证源码
docker compose exec backend grep -n "require_admin" app/api/admin/sensitive_words.py
# 预期输出:两行(import + dependencies

# 2) 普通坐席 token curl 13 端点(应全部 403
TOKEN_AGENT="<普通坐席 token>"
for endpoint in \
  "GET /api/admin/sensitive-words" \
  "POST /api/admin/sensitive-words/test" \
  "POST /api/admin/sensitive-words/reload" \
  "GET /api/admin/privacy-patterns" \
  "POST /api/admin/privacy-patterns/1/test" \
  "GET /api/admin/moderation-logs" \
  "GET /api/admin/moderation-logs/stats" \
  "GET /api/admin/moderation-config"; do
    METHOD=$(echo $endpoint | awk '{print $1}')
    PATH_=$(echo $endpoint | awk '{print $2}')
    curl -sS -X $METHOD "http://localhost:8000$PATH_" \
      -H "Authorization: Bearer $TOKEN_AGENT" -w "\nHTTP %{http_code}\n"
done
# 预期:全部 HTTP 403 + code:1004

# 3) admin token curl 13 端点(应全部 200
TOKEN_ADMIN="<admin token>"
# 同上循环,预期全部 HTTP 200

5.3 回归测试

  • TC-通用-004 既有 23/31 通过用例不变
  • 内容审核业务(坐席发消息审核)流程不变

6. 部署与回滚

6.1 部署步骤(按 jumpserver-V2 铁律)

  1. 本地构建产物:无需前端构建;后端无新依赖,pip install 不变
  2. 本地源码变更同步到 ASCII 构建路径(按 §11.7 多路径铁律):
    • 中文路径:D:\资料\03-项目开发\wecom_it_smart_desk\src\backend\app\api\admin\sensitive_words.py
    • ASCII 路径:D:\dev\wecom\src\backend\app\api\admin\sensitive_words.py
    • 两边都改
  3. 上传到生产
    # 走 psftp 通道(按部署铁律)
    psftp> put sensitive_words.py /<资产>/<系统用户>/
    
  4. 容器内操作
    # 远程禁用 $(),按铁律
    docker cp /tmp/sensitive_words.py wecom_it_backend:/app/app/api/admin/sensitive_words.py
    docker compose restart backend
    
  5. 验证:跑 §5.2 端到端 curl

6.2 回滚预案(30 min 可逆)

# 1) 恢复源码(git checkout HEAD~1 或手动删除 dependencies 那行)
docker cp /tmp/sensitive_words.py.bak wecom_it_backend:/app/app/api/admin/sensitive_words.py
# 2) 重启
docker compose restart backend
# 3) 验证:admin 仍可访问 13 端点(恢复裸奔状态)

回滚代价:再次陷入 13 端点裸奔状态(但仅 30 min 内应急,业务可接受)。

6.3 灰度开关

不需要灰度。修复本身就是"从危险→安全"的方向,无需开关


7. 风险与豁免

风险 等级 缓解
admin 误锁(token 过期) 🟢 401 不是 403,前端可正常重登录
修复不彻底(漏掉新端点) 🟢 本次仅 1 个文件 13 端点,APIRouter dependencies= 一行全覆盖
性能损耗 🟢 get_current_agent 缓存 JWT 解析;< 1ms 开销
require_admin 函数被改名 🟢 admin_api.py:50 已是稳定函数,6 个同类文件已引用
与 v1.2 部署冲突 🟢 独立部署,CI 可串行
修复后没跑端到端 🟠 强制走 §5.2 容器内 curl 验证,不信源码 grep

7.1 豁免清单

端点 豁免原因
无(13 端点全部要求 admin -

8. 关联文档

文档 位置 关联点
前置技术方案 v1.0 02-技术文档/技术架构/技术方案-REQ-通用-004-敏感词检测-v1.0.archive.md §6.3 路由层表格已规定 admin
关联 PRD v1.1.1 01-产品文档/00-产品规划/PRD-REQ-通用-004-敏感词检测-v1.1.1.md 需求来源
关联缺陷单 03-测试文档/05-缺陷单/BUG-通用-004-敏感词API无鉴权-001.md 触发
关联任务说明书 v1.1.1 07-项目管理/任务说明书/任务说明书-REQ-通用-004-敏感词检测-v1.1.1.md 任务清单
测试用例 03-测试文档/03-功能测试用例/TC-通用-004-敏感词检测.md 加 §10 鉴权章节
整改记录 04-运维文档/部署运维/00-文档规范化整改记录.md #5 整改
鉴权依赖定义 src/backend/app/api/admin_api.py:50-66 复用
同类已加鉴权文件 admin_api.py / admin_roles.py / admin_users.py / welcome.py / quiz_admin.py / troubleshooting_templates.py 对照实现
项目规范 docs/00-产品开发流程与文档管理规范.md v1.9 § 4.3 文档更新时机 + § 11 整改实践
多路径铁律 docs/00-产品开发流程与文档管理规范.md § 11.7 中文 + ASCII 双改
部署铁律 docs/00-产品开发流程与文档管理规范.md § 11.5-11.8 验证三证据链
部署排查手册 docs/04-运维文档/部署运维/00-标准故障排查手册.md 容器内操作参考

9. 变更日志

版本 日期 变更 变更人
v1.0 2026-07-28 首次整理:v0.7.1 上线内容回溯为正式技术方案 宋献
v1.1 2026-07-28 DB化 + 后台 UI + 13 端点实施(实施时漏加鉴权BUG-通用-004 宋献
v1.1.1 2026-08-05 PATCH 级别安全补漏:APIRouter 加 dependencies=[Depends(require_admin)]13 端点全覆盖 宋献 / Duckula

关键决策记录

  • 2026-08-05v1.1.1 作为 PATCH 级别安全补丁;不阻塞 v1.2 AI 化草案;operator_id 审计 / 正则复杂度限制列入 v1.1.2 或 v1.2 跟进
  • 强制规范沉淀:任何 APIRouter(prefix="/admin", ...) 必须声明 dependencies=[Depends(require_admin)],无显式豁免不得省略