文件
hyb-oa/issues/2026-04-12_r61-auth-refresh.csv

6.3 KiB

1IDTitleDescriptionAcceptanceTest_MethodToolsDev_StatusReview1_StatusRegression_StatusFilesDependenciesNotes
2A1R61 执行合同建档与范围冻结创建并校验 R61 Auth token refresh 主动续期执行合同 CSV,冻结范围:1) 后端 login/refresh/change-password 响应补充 expiresIn;2) 前端 AuthContext 增加主动 refresh 定时器;3) http 401 retry 失败时走静默 session-expired;4) reviewer/QA 收口。不新增 Prisma 迁移,不引入新依赖。issues/2026-04-12_r61-auth-refresh.csv 列完整、Dependencies 为 JSON 数组字符串、A2-A6 范围与当前方案一致,且不混入 Prisma 迁移或其他模块。命令:python3 /home/shunli/.codex/skills/plan/scripts/validate_issues_csv.py issues/2026-04-12_r61-auth-refresh.csv。检查:1) 对照 AGENTS.md 确认 12 列完整;2) A2-A6 依赖链合理;3) Notes 明确无迁移、无新依赖与回滚路径。manualDONEDONEDONEissues/2026-04-12_r61-auth-refresh.csv[]回滚路径:删除本次 CSV 不影响业务。
3A2后端认证响应补充 expiresIn在 server/src/routes/auth.js 内增加 access token TTL 秒数解析 helper,并为 POST /login、POST /refresh、POST /change-password 的 JSON 响应新增 expiresIn 字段;不改变现有字段结构。OIDC callback 保持 redirect-only,不改响应体。1) login/refresh/change-password 的 data 中均新增 expiresIn:number;2) expiresIn 与 config.accessTokenTtl 的秒数换算一致;3) 仅新增字段,不影响现有 accessToken/mustChangePassword 结构;4) OIDC callback 仍为 redirect-only。命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd server && node --check src/routes/auth.js。业务:调用 /api/auth/login、/api/auth/refresh、/api/auth/change-password,检查响应均带 expiresIn,且数值与 access token TTL 一致。manualDONEDONEDONEserver/src/routes/auth.js["A1"]回滚路径:移除 auth.js 中 expiresIn helper 与三个响应字段。无 Prisma 迁移。
4A3前端 AuthContext 主动 refresh 定时器在 client/src/auth/AuthContext.tsx 中读取 login/refresh/change-password 响应的 expiresIn,增加单例 setTimeout,在 expiresIn * 0.8 时主动调用 refreshSession;成功后更新 accessToken 并重置定时器,失败时保留现有被动 refresh 兜底。1) 登录、bootstrap refresh、被动 refresh、改密成功后都会调度下一次主动 refresh;2) 任意时刻仅存在一个活跃 refresh 定时器;3) clearSession 与组件卸载时会清除定时器;4) 主动 refresh 失败不会直接 clearSession,仍保留现有 401 被动 refresh。命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd client && npm run typecheck && npm run build。业务:1) 登录后确认主动 refresh 定时器启动;2) refresh 成功后 token 更新且不会生成重复定时器;3) 登出后定时器被清理。manualDONEDONEDONEclient/src/auth/AuthContext.tsx|client/src/auth/authService.ts|client/src/api/auth.ts|client/src/api/types.ts["A2"]回滚路径:移除 AuthContext 主动 refresh 调度逻辑,恢复仅 401 被动 refresh。保持 LoginResponse 兼容。
5A4前端 401 retry 失败静默收口在 client/src/api/http.ts 中为 refresh 失败后的 401 retry 引入静默 session-expired 错误,不再继续解析原始 401 响应并构造普通 ApiError;bootstrap refresh 失败继续保持已 catch 的静默处理。1) sendRequest 在 refresh 返回 null 后直接抛出专用 session-expired 错误;2) 不再对原始 401 响应执行 safeParseJson + buildApiError;3) clearSession 仍会执行,且不会产生 unhandled rejection;4) 不吞掉其他非 session-expired API 错误。命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd client && npm run typecheck && npm run build。业务:1) 模拟 refresh token 失效,原请求 401 后进入静默 session-expired 路径;2) bootstrapByRefresh 的 refresh 401 不产生未处理 Promise rejection。manualDONEDONEDONEclient/src/api/http.ts|client/src/api/types.ts|client/src/auth/AuthContext.tsx["A3"]回滚路径:移除 session-expired 专用错误与静默分支,恢复原有 ApiError 行为。
6A5Reviewer 复核定时器与刷新竞态复核主动 refresh 定时器、被动 refresh 兜底与 session-expired 收口,重点检查是否存在多定时器、并发 refresh、安全泄露或异常吞噬问题。1) clearSession 和卸载路径都能清理定时器;2) 同时存在主动 refresh 与被动 refresh 触发时不会并发发起多次 refresh;3) expiresIn 不会导致敏感信息泄露;4) SessionExpiredError 仅用于静默会话过期。Review:检查 AuthContext/http/types 变更,确认 refresh 调度为单例、失败路径清晰、无 token 日志输出。必要时手工验证登录后改密、登出、过期会话三条路径。manualDONEDONEDONEclient/src/auth/AuthContext.tsx|client/src/api/http.ts|client/src/api/types.ts|server/src/routes/auth.js["A2","A3","A4"]回滚路径:若 reviewer 发现关键竞态或安全问题,暂停提交并回退对应代码。
7A6QA、状态回填与提交收口执行 R61 post-check 与手工验证,回填 CSV 状态并完成提交收口,确保主动 refresh 不引入回归。后端语法检查、前端 typecheck/build 通过;登录、主动 refresh、被动 refresh 兜底、refresh 失效静默退出流程验证通过;issues/2026-04-12_r61-auth-refresh.csv 三列状态按结果回填。命令:export PATH=/home/shunli/.nvm/versions/node/v22.20.0/bin:$PATH && cd server && node --check src/routes/auth.js && cd ../client && npm run typecheck && npm run build。业务:1) 登录成功后触发主动 refresh 调度;2) 主动 refresh 成功后不会出现重复定时器;3) refresh token 失效时会静默清会话,减少多余 console 错误;4) 改密后仍会调度主动 refresh。manualDONEDONEDONEissues/2026-04-12_r61-auth-refresh.csv|server/src/routes/auth.js|client/src/auth/AuthContext.tsx|client/src/api/http.ts|client/src/api/types.ts["A5"]回滚路径:若 post-check 或手工验证失败,暂停提交并回退 R61 代码。commit message:R61 A1-A6:Auth token refresh 主动续期。