# Phase 4 用户端审核报告(T-501 ~ T-504) > 审核人:Claude Code(全栈视角)|日期:2026-07-03|结论:**功能验收全部达标,测试覆盖极全,零 P1(无安全/资金/越权缺陷)**。 > Phase 4 是自助用户端(Django 模板 SSR + allauth)。逐条比对当时验收:注册不送点数、session+CSRF、越权(IDOR)防护、API Key 明文只显一次、吊销后调用 403、记录仅见本人、充值到账以回调为权威——**全部正确落地且有专测**。2026-07-08 新需求已由 T-608 改为「新用户注册送 100 点」,本报告保留历史审核口径。剩余为前端资源与 UX 优化项(P2/P3)。 > 本文面向 codex 执行:每条给出「症状 / 位置 / 怎么改 / 怎么验证」。修补任务见 [`06-tasks.md`](06-tasks.md) 的 **T-505**;按任务看板领取规则,当前应先完成 T-505,再进入 T-401。 ## 一、验收核对(功能全部达标) | 任务 | 验收要点 | 结果 | | --- | --- | --- | | T-501 | 自助注册(邮箱验证)、登录、登出;注册后钱包 0 点(不送点数);session+CSRF | ✅ 注册建 0 点钱包且**不写 `PointsLedger`**(专测);未验证邮箱不能登录;登录 POST CSRF 保护 | | T-502 | 生成/删除 Key;明文只显一次、库内只存哈希;列表只显 prefix;删除即吊销、吊销后调用 403 | ✅ 全部专测覆盖,含「删除→外部 API 返回 403」与「不能删他人 Key」(IDOR) | | T-503 | 剩余点数、充值总额、充值/消费记录;数据与流水一致;仅见本人 | ✅ 余额/汇总同源于流水;三处记录页均按 `user=request.user` 过滤(专测越权) | | T-504 | 发起充值→二维码→轮询→到账刷新;到账以回调为权威 | ✅ 下单**不加点不写流水**(专测);轮询 T-305 status 端点;paid 后 reload;入账仍走幂等回调/查单 | ## 二、做对的(勿在修补中回退) 1. **注册不送点数、且不留误导流水**:`CmhubAccountAdapter.save_user` 在事务内 `get_or_create` 建 `points_balance=0` 钱包,**刻意不写任何 `PointsLedger`**(避免被误解为赠点);专测断言注册后 0 点、无流水。顺带解决了 Phase 2 P3「钱包应在注册时创建」——precharge 不再依赖热路径建钱包。 2. **越权(IDOR)防护到位**:删除 Key 用 `get_object_or_404(ApiKey, pk=pk, user=request.user)`(他人 Key 返回 404 不泄露存在性);所有记录/订单查询一律 `filter(user=request.user)`;充值页 `current_order` 也按 user 过滤。每条都有「只见本人」专测。 3. **API Key 明文只显一次**:生成后 `raw_key` 存入 session,下次渲染 `session.pop` 取出展示后即清除(PRG 模式);刷新不再出现;库内只存 `key_hash`+`key_prefix`。专测断言明文只显一次、库内只存哈希。 4. **删除=吊销(软删)**:`status→revoked` 而非物理删除,保留审计与 `CallRecord` 关联;吊销后外部 API 返回 403(与 T-301 口径一致:revoked→403、缺失/无效→401)。codex 主动修正了任务原文的「401」为正确的「403」。 5. **session+CSRF 全覆盖**:所有页面 `LoginRequiredMixin`;所有 POST 表单带 `{% csrf_token %}`;登录、建/删 Key、充值下单的 CSRF 都有专测。 6. **充值到账以回调为权威**:下单只建 `pending` 订单、**不碰余额**;前端轮询 `api-recharge-status`(`same-origin` 会话),status 端点内部对 pending 单走 `query_and_apply_recharge_payment`(复用幂等、金额校验的 `apply_recharge_payment`);paid 后 reload 刷新余额。资金入账始终经计费层,页面只读。 7. **记录与流水同源**:余额用 `get_balance_snapshot()`;充值总额按 paid `RechargeOrder.amount_money`;入账/消费按 `PointsLedger` 汇总;`net_used_points = 消费 − 退款`(退款 delta 为正、消费取绝对值,口径正确)。 8. **用当前 allauth API**:`ACCOUNT_LOGIN_METHODS` / `ACCOUNT_SIGNUP_FIELDS`(65.x 新式设置)、`ACCOUNT_EMAIL_VERIFICATION="mandatory"`、`ACCOUNT_UNIQUE_EMAIL`,与 T-201 的 `User.email` 唯一约束对齐。未引入 crispy-forms(MVP 保持轻)。 ## 三、优化建议 / 修补清单 ### P1 · 现在改 **无。** 用户端零 P1——越权、CSRF、注册不送点、明文只显一次、吊销 403、到账以回调为权威全部正确且有测试。以下为前端资源与 UX 优化。 ### P2 · 建议处理 #### P2-1 外部 CDN 无 SRI + 国内可用性(含支付页) - **症状**:`base.html` 从 jsdelivr 加载 Bootstrap CSS、`recharge.html` 从 jsdelivr 加载 `qrcode.min.js`,**均无 `integrity`(SRI)/`crossorigin`**。两个问题: 1. **供应链/XSS**:无 SRI 的 `