diff --git a/qy_lty/docs/修改记录.md b/qy_lty/docs/修改记录.md index 66921aa..5088312 100644 --- a/qy_lty/docs/修改记录.md +++ b/qy_lty/docs/修改记录.md @@ -23,6 +23,29 @@ +### [2026-05-08] Phase 3 — 客户端凭据槽位 GET 接口 + 阿里云日志 access_token 脱敏 + +配套 Phase:[.planning/phases/03-client-and-log-mask/](.planning/phases/03-client-and-log-mask/) +覆盖需求:CRED-05 + CRED-06 +设计参考:1:1 复刻 `aiapp.views.CredentialSlotAdminView` 的 GET 部分(删 `_ensure_admin` / `_build_response_data` / PUT 三处),实现明文返回客户端 view;新建 `common/logging/filters.py:AccessTokenMaskFilter` 作为 LOGGING.handlers 层防御性兜底 + +- **文件路径**: + - `aiapp/views.py`(修改 — 文件末尾追加 `_credential_slot_client_data_schema` 客户端响应 schema + `CredentialSlotClientView` APIView 类,仅 GET,明文返回;imports 段未动;Phase 2 既有 `CredentialSlotAdminView` 未动) + - `qy_lty/urls.py`(修改 — imports 段追加 `from aiapp.views import CredentialSlotClientView`;`api_urlpatterns` 列表中追加 `path('credential-slot/', CredentialSlotClientView.as_view(), name='client_credential_slot')`,注册位置:`common/upload/` 之后、`v1/admin/` 之前) + - `common/logging/__init__.py`(**新建** — 空文件,让 `common.logging` 成为可 import 的 Python 包) + - `common/logging/filters.py`(**新建** — `AccessTokenMaskFilter(logging.Filter)` 类 + 4 个 regex 模式(JSON / Python dict repr / URL query / 等号或冒号兜底)+ `filter()` 方法重写 `record.msg` 与 `record.args` 中的 access_token 字段值为 `mask_token(value)` 输出) + - `qy_lty/settings.py`(修改 — `LOGGING` 字典新增 `'filters'` 段(用 `'()': 'common.logging.filters.AccessTokenMaskFilter'` dictConfig 工厂语法);`'handlers'.aliyun` 与 `'handlers'.console` 各追加 `'filters': ['access_token_mask']`;loggers 段 5 条 logger 完全未动) +- **修改类型**: 新增 +- **修改内容**: + - 暴露 `GET /api/credential-slot/`(路径与管理端 `/api/v1/admin/credential-slot/` **完全分开**,客户端走 `/api/` 一级命名空间不进 `v1/admin/` 子路径):`RedisTokenAuthentication` + `IsAuthenticated`,**不**做 is_staff 二次校验(admin / user token 都允许;admin 用户是手机用户超集,CONTEXT 锁定决策);返回 `{ success, code, message, data: { app_id, access_token: <**明文**>, updated_at } }`,Access Token 直接返回 `serializer.data`(不调 `mask_token`),供手机端(LTY_App_Project_URP)/ 设备端(LTY_Project)实际调用阿里云 / 火山 / 腾讯第三方服务 + - 新建 `AccessTokenMaskFilter`:4 个正则模式覆盖 JSON 字符串(`"access_token":"VALUE"`)、Python dict repr(`'access_token':'VALUE'`)、URL query(`access_token=VALUE`)、等号或冒号兜底(`access_token: VALUE`)共 4 种序列化形态;filter 同时改 `record.msg` 与 `record.args`(避免 Formatter 阶段再用 `%` 拼接出明文,per RESEARCH Pitfall 2);只匹配 `access_token` 字段名为前缀锚点,**不**误伤 `Authorization header:` / `Bearer` / 裸 user token(per RESEARCH Pitfall 3);filter 永远 `return True` 不丢弃 record(per RESEARCH Pitfall 1) + - LOGGING dictConfig 注册:filter 段用 `'()': '...'` 工厂语法(不是 `'class'`,per RESEARCH Pitfall 5);filter 挂在 `handlers.aliyun` / `handlers.console` 两个 handler 上(**不**挂 loggers 段,per RESEARCH Pitfall 1 — 挂 logger 仅过滤直接通过该 logger 的 record,挂 handler 才统一覆盖所有 logger → handler 路径);既有 5 条 logger 配置完全未动 + - Swagger / ReDoc 自动暴露:method-level `@swagger_auto_schema` 装饰器;响应 data schema 用独立 `_credential_slot_client_data_schema`,access_token 字段 description 显式标注「明文 Access Token,供手机/设备端实际调用第三方服务(管理端同接口会脱敏返回末 4 位)」,避免前端误解明文 / 脱敏 + - 不引入新依赖(沿用 Django 4.2.13 + DRF + drf-yasg + Phase 1/2 落地的 `CredentialSlot.get_solo` / `CredentialSlotSerializer` / `mask_token`) +- **修改原因**: Milestone v1.0「通用凭据槽位(APP ID + Access Token)」Phase 3 收尾 phase — 同时落地客户端读取(CRED-05)与日志脱敏(CRED-06)。客户端读取需要明文(手机/设备端 Unity 调阿里云 / 火山 / 腾讯 SDK 时第三方 API 校验 token 字符级一致),所以 view 层不脱敏;但「明文走 view」会让任何后续开发者写 `logger.info(f"PUT body: {request.data}")` 类代码立即把 access_token 打到阿里云日志服务,所以新增 LOGGING.handlers 层 filter 作为防御性兜底。RESEARCH 已实证:当前仓库**没有**任何代码 logger 输出 `CredentialSlot.access_token` 明文(`StandardResponseMiddleware` 不打日志、view 不显式 logger 字段、Django 默认 access log 不含 body),所以 CRED-06 的端到端验证靠**单元测试**伪造 LogRecord 验证 filter 行为(4 种序列化形态 + 不误伤 Authorization 字段)+ 1 条端到端 logger.info 真实输出脱敏验证,不靠端到端找泄露路径。这是 CRED-06 的真实价值 — 防御性兜底,让未来代码改动天然安全 +- **跨项目联动**: 无 — 客户端 GET `/api/credential-slot/` 给 Unity 客户端(`LTY_Project` / `LTY_App_Project_URP`)使用,那两个 repo 各自维护修改记录,不在本仓库范畴;`qy-lty-admin`(Web 管理后台前端)**不消费**此接口(管理端走 Phase 2 落地的 `/api/v1/admin/credential-slot/`,由 admin token 鉴权 + 脱敏返回)。CLAUDE.md 跨项目规则下:本 phase 既不影响 qy-lty-admin 也不与 Unity 客户端在同一仓库,故不在 qy-lty-admin/docs/修改记录.md 写互引条目;Unity 客户端改动由 LTY_Project / LTY_App_Project_URP 在自身仓库各自记录 +- **后续动作**: Milestone v1.0 至此完成;下一周期 milestone 候选见 `.planning/REQUIREMENTS.md` 「候选优先级」段(HIGH:ACH-02 / SMS 频率限制 / DEBUG 收紧 / 测试基础设施 / 测试 MAC 硬编码;MEDIUM:好感度 P2-P4 / Python 版本升级 / device_interaction 拆分) + ### [2026-05-07] Phase 2 — 管理端通用凭据槽位 REST 接口(GET 脱敏 / PUT 覆写) 配套 Phase:[.planning/phases/02-admin-rest/](.planning/phases/02-admin-rest/)