You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

13 KiB

R01-A5 独立代码复验报告(第五批:8 个 Controller 请求身份与 requestId 收束)

日期:2026-09-17 分支:refactor/r01-structure-performance HEAD:0226977063243fce101e3f6c8dcf66492d306ef7(A4 后最新提交,复验全程未变) 复验对象:docs/r01-a5-request-context-migration-report.md 性质:仅复验 —— 未修改生产代码、未修改既有测试断言、未暂存、未提交、未推送


0. 结论

R01-A5独立代码复验通过,可以进入精确暂存、本地提交与推送检查点。

FAIL = 0;SKIP = 0。未发现生产缺陷。


1. 开始前状态

检查项 结果
分支 refactor/r01-structure-performance ✔
HEAD 0226977063243fce101e3f6c8dcf66492d306ef7(A4 后最新)✔
与上游同步 0 / 0 ✔
暂存区 空 ✔
git diff --check 无空白错误 ✔
工作区改动 仅 8 个 A5 Controller + 路线图,无 A5 之外的生产代码改动 ✔
历史未跟踪文件 全部保留 ✔
reset/restore/checkout/clean、git add -A、Docker 均未执行 ✔

GlobalExceptionHandler.java 三方 blob 比对

来源 blob
worktree(git hash-object) 1fdc341ebe3653393b3ec04f0c2d0bb9dfbb6d21
index(git ls-files -s) 1fdc341ebe3653393b3ec04f0c2d0bb9dfbb6d21
HEAD(git rev-parse HEAD:<path>) 1fdc341ebe3653393b3ec04f0c2d0bb9dfbb6d21

三者完全一致 → 纯 Windows stat 缓存现象,未触碰该文件 ✔


2. 8 个 Controller 静态审查

Controller 代表端点 Accessor 调用(auth / reqId)
CandidateScoringGovernanceController GET /profile/me/candidate-scoring/appeals 9 / 9
InterviewScoreController GET /interviews/{id}/score 4 / 4
FavoriteController GET /jobs/favorites 3 / 3
AdminReviewController GET /admin/reviews/pending 3 / 3
AdminReviewReplyController GET /admin/review-replies/pending 2 / 2
CompanyReviewManagementController GET /companies/me/job-reviews 4 / 4
JobReviewController DELETE /jobs/{jobId}/reviews/{reviewId} 3 / 7
StudentReviewWeightController GET /profile/me/review-weights 3 / 4

(JobReviewController / StudentReviewWeightController 的 reqId 调用数高于 auth 属正常 —— 部分只读端点只需 requestId。)

改动性质:8 files changed, 101 insertions(+), 198 deletions(-),删除的 ErrorCode.UNAUTHORIZED 共 10 处,全部来自被移除的私有解析方法;角色检查(assertAdminRole/assertCompanyOwner/assertStudentRole)、资源归属、FORBIDDEN/NOT_FOUND 及 Service 调用顺序未删未增、未移动 ✔

JobReviewController.parseIds 完整保留 ✔ —— 它解析 ids 查询参数(业务参数,非认证主体),并以 catch (NumberFormatException) → BAD_REQUEST 处理,属正确的业务参数语义,未被误删或误判。


3. 禁止模式扫描

任务书指定模式在 8 个文件中的命中:全部为 0 ✔

覆盖:SecurityContextHolder、AnonymousAuthenticationToken、anonymousUser、auth.getName()、authentication.getName()、Long.(valueOf|parseLong)(...(auth|authentication)、private (resolveUserId|getRequestId|requestId)(、getHeader(...X-Request-Id|REQUEST_ID_HEADER)、@Autowired(required=false)、@Nullable、ObjectProvider、new CurrentUserAccessor、new RequestIdAccessor


4. 构造器注入与无回退证明

8 个 Controller 均声明:

private final CurrentUserAccessor currentUserAccessor;
private final RequestIdAccessor requestIdAccessor;
  • 全部为 private final 构造器注入(Lombok @RequiredArgsConstructor)✔
  • 无 @Autowired(required = false) / @Nullable / ObjectProvider / new CurrentUserAccessor() / new RequestIdAccessor() 回退 ✔
  • 身份统一为 currentUserAccessor.requireUserId();requestId 统一为 requestIdAccessor.get(request) ✔

5. 独立接线变异测试(Accessor 真实生效的证明)

新增 A5AccessorWiringIndependentTest(4 例),不复用实施者断言,使用 @MockBean 替换 CurrentUserAccessor、RequestIdAccessor 与 8 个 Service:

用例 证明
allEightEndpoints_useAccessorUserId mock 返回 4242L → 逐一验证 8 个 Service 均收到 4242L(listMyAppeals / getScore / listFavorites / listPendingReviews / listPending / listMine / deleteReview / getMyWeights),并 verify(currentUserAccessor, times(8)).requireUserId()
illegalIdentity_rejectedBeforeService mock 抛 InsufficientAuthenticationException → 8 端点全部 401、无 500,且各 Service 零调用
responseBodyRequestId_comesFromAccessor mock 返回 a5-independent-request → 8 个端点响应体 requestId 均为该值,verify(requestIdAccessor, times(8)).get(...)
noToken_is401 无 Token → Security 链 401

变异有效性:若删除任一 Controller 中的 currentUserAccessor.requireUserId() 或 requestIdAccessor.get(request) 调用,对应 verify 与断言必然失败 —— 即删除 Accessor 调用会使本测试失败 ✔

说明:响应头 X-Request-Id 由 RequestIdFilter 设置,不来自 Controller;本测试只断言响应体的 requestId 来源于 Accessor,未错误声称响应头来源。


6. 八端点非法主体结果(独立身份边界复验)

A5IndependentVerificationTest 使用真实 CurrentUserAccessor 与真实 SecurityFilterChain(不 mock Accessor):

主体 结果
anonymousUser 401 ✔
not-a-number 401 ✔
99999999999999999999(20 位溢出) 401 ✔
0 401 ✔
-1 401 ✔
AnonymousAuthenticationToken / 无 Token 401 ✔

逐端点断言(7 个 GET 端点 + DELETE /jobs/1/reviews/1):

  • HTTP 401,无 500 ✔
  • 业务 Service 零调用 ✔(verify(..., never()))
  • 不回显非法主体 —— 仅解析 JSON 后检查 code/message 稳定字段,未对整段 JSON 做数字搜索 ✔
  • 响应不包含 Exception / java. / principal / anonymousUser / com.mydreamjob / NumberFormat ✔

未使用任何捕获 NumberFormatException 的方式"修复"测试。


7. 合法主体传入 Service 的 userId 证据

§5 的 verify 系列即为证据:mock Accessor 返回 4242L 时,8 个 Service 各自收到 4242L(逐一 eq(4242L) 断言)✔

同时 A5IndependentVerificationTest#legalPrincipal_reachesService 使用真实 Accessor(数字主体 "7")验证 8 端点不被身份层判为未登录(非 401)✔


8. requestId Accessor 接线证据

见 §5 第 3 项:mock RequestIdAccessor#get 返回固定值 → 8 个端点(7 个 GET + 1 个 DELETE,均返回 ApiResponse)响应体 requestId 均为 a5-independent-request,并 verify(requestIdAccessor, times(8)).get(any(HttpServletRequest.class)) ✔


9. 401 / 403 / 404 分层保持

检查项 结果
静态审查:角色/归属检查是否被删改或移动 否(git diff 确认未删未增)✔
FORBIDDEN / NOT_FOUND 错误码 未修改 ✔
ErrorCode.java 零改动 ✔
合法主体不被判为未登录 ✔(§7)

401 与 403/404 的分层未被统一:身份失败为 401,角色/归属失败仍由既有 Service 逻辑产生 403/404,语义未漂移。


10. 失败请求的业务副作用

新增 A5SideEffectSnapshotTest(2 例),使用 H2 行级快照(显式列 + 稳定 ORDER BY,逐字段比较,非 COUNT/SUM):

快照覆盖 9 张核心表:JOB_FAVORITES、JOB_REVIEWS、COMPANY_REVIEW_REPLIES、INTERVIEW_SCORES、CANDIDATE_SCORING_APPEALS、STUDENT_REVIEW_WEIGHT_PREFERENCES、NOTIFICATIONS、MESSAGES、AUDIT_LOGS。

用例 结果
非法身份请求(anonymousUser + not-a-number × 7 端点 + DELETE)前后 9 张表逐字段零变化 ✔
无 Token 请求前后 9 张表逐字段零变化 ✔

结论:非法身份请求不写收藏、评价、回复、面试评分、治理申诉、权重;不发通知;不发 RabbitMQ 消息;不写审计成功记录(AUDIT_LOGS 零变化)✔

本轮未启动 Docker,以上为 H2 独立复验结论;不声称真实 MySQL 结论。


11. 测试数

命令 结果
mvn -Dtest="A5AccessorWiringIndependentTest,A5IndependentVerificationTest" test 8 / 8,F=0 E=0 S=0
mvn -Dtest="A5SideEffectSnapshotTest" test 2 / 2,F=0 E=0 S=0
A5 定向(R01A5…,A5*Test, 8 个 Controller 测试 + 3 个 Accessor/Filter 测试) 98 / 98,F=0 E=0 S=0,BUILD SUCCESS
mvn clean verify 2255 / 2255,Failures=0、Errors=0、Skipped=0,BUILD SUCCESS
  • 实施基线 2245 → 复验后 2255(新增 10 个独立测试:4 + 4 + 2),不低于基线 ✔
  • 未见新的基线测试污染 ✔

12. OpenAPI

python docs\verify_openapi.py → 176 paths / 214 operations,All checks passed ✔

docs/openapi-rc.json 零修改 ✔


13. Flyway / ErrorCode / DTO / 接口

项 结果
V1–V45 迁移 零修改(git diff --name-only -- db/migration 为空)✔
ErrorCode.java 零改动 ✔
DTO 零改动 ✔
公网接口 / OpenAPI 零新增零修改 ✔
新增表 / 索引 无 ✔

14. 全仓剩余统计(逐文件分类)

身份解析(SecurityContextHolder.getContext().getAuthentication | Long.(valueOf|parseLong)([^)]*getName())—— 4 文件

分类 文件
基础设施(3) security/CurrentUserAccessor(Accessor 自身)、auth/JwtAuthenticationFilter(认证过滤器)、deletion/DeletionGuardInterceptor(拦截器)
业务 Controller(1) scoringmonitoring/FairnessMonitoringController
误报 0

requestId 解析(含 X-Request-Id 直读、RequestIdFilter.REQUEST_ID_HEADER、String (getRequestId|resolveRequestId|requestId)()—— 10 文件

分类 文件
基础设施 / 非业务入口(5) audit/AuditContext、common/exception/GlobalExceptionHandler、common/logging/RequestIdAccessor、common/logging/RequestLoggingFilter、deletion/DeletionGuardInterceptor
业务 Controller(5) controller/ApiController、controller/AuthController、controller/SystemController、job/JobController、scoringmonitoring/FairnessMonitoringController
误报 0

与路线图记数的一处差异(如实记录):路线图 R01 行记「全仓 requestId 11 文件 = 基础设施/非业务入口 6 + 业务 5」。本次独立复验用任务书指定模式实测为 10 文件 = 基础设施 5 + 业务 5。业务 Controller 数一致(5);差异在基础设施计数(5 vs 6),推测为路线图对"基础设施/非业务入口"的分类口径略有不同(如是否计入某调用点)。不应据此修改代码或路线图;建议后续批次统一口径。


15. 精确新增文件

新增测试(3)
  mydreamjob-server/src/test/java/com/mydreamjob/common/r01a5/A5AccessorWiringIndependentTest.java
  mydreamjob-server/src/test/java/com/mydreamjob/common/r01a5/A5IndependentVerificationTest.java
  mydreamjob-server/src/test/java/com/mydreamjob/common/r01a5/A5SideEffectSnapshotTest.java

复验报告(1)
  docs/r01-a5-independent-verification-20260917.md

未修改:8 个 A5 Controller 生产代码、既有测试断言、GlobalExceptionHandler、SecurityConfig、Filter、Accessor、ErrorCode、DTO、OpenAPI、Flyway。


16. Git 状态

分支:refactor/r01-structure-performance
HEAD:0226977063243fce101e3f6c8dcf66492d306ef7(未变)
暂存区:空
git add -A / commit / push:均未执行
reset / restore / checkout / clean:均未执行
Docker:未操作
工作区:8 个 A5 Controller + 路线图(实施者改动,仍未暂存)+ 本报告与 3 个独立测试(未跟踪)
历史未跟踪文件:全部保留

17. 是否发现生产缺陷

未发现生产缺陷。 8 个 Controller 的迁移完整、正确:

  • 禁止模式 0 命中;构造器注入无回退;parseIds 业务解析正确保留
  • 角色/归属/403/404 语义未漂移
  • 独立接线变异测试证明 Accessor 真实生效(删除调用即失败)
  • 独立身份边界测试证明非法主体在业务调用前被拒(401、无 500、零 Service 调用)且不回显主体
  • 失败请求 9 张核心表逐字段零变化

18. 明确声明

  • 未暂存、未提交、未推送。
  • 未修改 8 个 Controller 或任何生产代码;未修改、删除或放宽既有测试断言;未修改 GlobalExceptionHandler、SecurityConfig、Filter、Accessor、ErrorCode、DTO、OpenAPI、Flyway。
  • 未进入 R01-A6;未删除历史未跟踪文件。
  • 本轮未启动 Docker,未伪造真实 MySQL 结论。

R01-A5独立代码复验通过,可以进入精确暂存、本地提交与推送检查点。