## 1. 签名工具与 Nonce 缓存 - [x] 1.1 新建 `UtilSignature.java`:sha256Hex + sign(HMAC-SHA256) + safeEquals(常量时间比较) - [x] 1.2 新建 `NonceCache.java`:基于 Hutool TimedCache,TTL=window+30s,synchronized putIfAbsent - [ ] 1.3 单元测试:`UtilSignatureTest`(阻塞 Maven 未装) - [ ] 1.4 单元测试:`NonceCacheTest`(阻塞 Maven 未装) ## 2. 配置与注解 - [x] 2.1 新建 `AuthConfigProperties`(prefix mjava.auth,默认值齐全) - [ ] 2.2 ~~独立 AuthConfig~~:不需要,AuthConfigProperties @Component 足够 - [x] 2.3 新建 `NoAuth` 注解(METHOD + TYPE) - [x] 2.4 `application.yml` 新增 mjava.auth.* 段,默认 enabled=false + ${AUTH_SECRET} 占位 - [ ] 2.5 子模块 application-*.yml.example(延后,启用时同步) ## 3. Filter + Interceptor 两层 - [x] 3.1 `AuthFilter`:@Order(HIGHEST+20) 位于 TraceIdFilter 后;enabled/exempt 放行;Header + 时间戳窗口 + Nonce - [x] 3.2 靠 @Component + @Order 自动注册到 Spring Boot Filter 链 - [x] 3.3 `AuthInterceptor`:preHandle 识别 @NoAuth + 读 body + 签名校验 + safeEquals - [x] 3.4 WebConfiguration 注册 AuthInterceptor - [x] 3.5 失败返回 `McR.error(code, message)` + 对应 HTTP 状态 ## 4. 审计日志集成 - [x] 4.1 AuthFilter / AuthInterceptor 失败分支 log.warn(point logger) - [x] 4.2 成功路径写 MDC authKey,finally 清理 - [ ] 4.3 logback pattern 追加 `[%X{authKey:-}]`(延后) ## 5. 参考客户端实现(文档侧) - [ ] 5.1 Java 客户端签名示例(工具类形式,便于其他 Java 系统 copy) - [ ] 5.2 Python 客户端签名示例(`requests` + `hmac`) - [ ] 5.3 Node.js 客户端签名示例(`node:crypto`) - [ ] 5.4 curl + openssl 命令行示例(方便临时调试) ## 6. 回归测试 - [ ] 6.1 `AuthFilterTest`:enabled/disabled 切换、Header 缺失、时间窗边界、Nonce 重放 - [ ] 6.2 `AuthInterceptorTest`:`@NoAuth` 方法级/类级、签名校验、exempt-paths - [ ] 6.3 集成测试:mjava-mcli 开启后用签名客户端调一次 → 成功;改签名 → 403;改时间戳 → 401 - [ ] 6.4 mcli/shunfeng/guangming **保持 `enabled: false`** 场景回归(零破坏验证) ## 7. 文档 - [ ] 7.1 `/Users/malk/Desktop/Tech/claude/后端/mjava-baseline.md` 新增 §13(或合并到 §6)"请求鉴权与防重放"章节,含签名协议与开关 - [ ] 7.2 README.md(本 change 完成后):客户端签名接入指引 - [ ] 7.3 BACKLOG.md 更新专项状态 ## 8. 验证 - [ ] 8.1 `openspec validate add-request-auth-replay-guard --strict` 通过 - [ ] 8.2 开启 enabled 后用 `curl + openssl` 跑通一次真实请求 - [ ] 8.3 Nonce 重放测试:同签名连发两次 → 第二次 401 ## 9. 交付 - [ ] 9.1 PR 附签名协议示意图 - [ ] 9.2 走 `/opsx:archive`