Files
Genarrative/.hermes/skills/genarrative-auth-session-flow/SKILL.md
历冰郁-hermes版 7e35231dfe
Some checks failed
CI / verify (pull_request) Has been cancelled
docs: sync genarrative shared skills
2026-05-08 17:39:49 +08:00

7.0 KiB
Raw Blame History

name, description, version, author, license, metadata
name description version author license metadata
genarrative-auth-session-flow 在 Genarrative 中排查或修改登录、access token、refresh cookie、AuthGate 会话恢复、登录态刷新、认证埋点链路时使用。 1.0.0 Hermes Agent MIT
hermes
tags related_skills
Genarrative
auth
session
cookie
refresh-token
AuthGate
tracking
systematic-debugging
test-driven-development
genarrative-profile-features

Genarrative 认证会话与登录埋点链路

用于 Genarrative 中登录、会话恢复、refresh cookie 续期、access token 补票、AuthGate 恢复登录态,以及每日登录/认证相关埋点的排查与修改。

适用场景

  • 用户反馈登录态、cookie、自动续期、刷新页面后状态异常。
  • 修改 AuthGateapiClientauthService 或 Rust api-server 认证接口。
  • 排查“已登录但打开网页没有触发登录埋点”等 session restore 场景。
  • 修改手机验证码登录、密码登录、微信登录、重置密码后自动登录、refresh session rotate。
  • 需要判断某个前端动作是否真正调用了后端 refresh/session 或埋点 procedure。

关键代码路径

前端:

  • src/components/auth/AuthGate.tsx
    • 登录态 hydrate / restore 的入口。
    • 监听 AUTH_STATE_EVENT 后重新 hydrate。
    • 是否先 refresh、再 /api/auth/me,决定打开页面是否进入后端 refresh 链路。
  • src/services/apiClient.ts
    • access token 本地保存、ensureStoredAccessToken()refreshStoredAccessToken()fetchWithApiAuth()
    • ensureStoredAccessToken() 有 token 时会直接复用,不一定触发后端 refresh。
    • refreshStoredAccessToken() 应直接调用 refresh 接口,用于必须轮换 cookie / 写续期埋点的场景。
  • src/services/authService.ts
    • getCurrentAuthUser() 请求 /api/auth/me
    • 登录、登出、账号安全相关 API client。

后端:

  • server-rs/crates/api-server/src/auth_session.rs
    • 创建 refresh cookie / access token。
    • record_daily_login_tracking_event_after_auth_success(...) 统一写每日登录埋点;失败 warning不阻断认证流程。
  • server-rs/crates/api-server/src/refresh_session.rs
    • POST /api/auth/session/refresh
    • rotate refresh session、签发新 access token、记录每日登录埋点。
  • server-rs/crates/api-server/src/auth_me.rs
    • /api/auth/me 只读取当前 access token 对应用户,不应假设它会触发 refresh 或登录埋点。
  • server-rs/crates/api-server/src/phone_auth.rs
  • server-rs/crates/api-server/src/password_entry.rs
  • server-rs/crates/api-server/src/password_management.rs
  • server-rs/crates/api-server/src/wechat_auth.rs
    • 各真实认证成功入口。
  • server-rs/crates/spacetime-client/src/runtime.rs
    • record_daily_login_tracking_event(user_id) 调用 SpacetimeDB procedure。
  • server-rs/crates/spacetime-module/src/runtime/profile.rs
    • record_daily_login_tracking_event_and_return procedure。
    • 任务中心读取不应污染每日登录埋点;如看到 get_profile_task_center 顺手写 daily_login,优先复核是否回归。

调试顺序

  1. 先明确用户场景属于哪类:
    • 新登录成功。
    • cookie/access token 已过期后的自动刷新。
    • 已登录且 cookie/access token 未过期时打开网页。
    • 只调用 /api/auth/me 或某个受保护业务接口。
  2. 查前端实际调用链,不要只看后端埋点点位:
    • AuthGate hydrate 是否调用 refreshStoredAccessToken()
    • 是否只是 ensureStoredAccessToken() + /api/auth/me
    • fetchWithApiAuth() 是否因为已有 access token 而跳过 refresh
  3. 查后端实际埋点点位:
    • 登录成功入口是否在 session 创建后调用 helper。
    • refresh session 是否在 rotate 与 access token 签发成功后调用 helper。
    • 失败策略是否只 warning、不阻断响应。
  4. 如涉及 SpacetimeDB procedure/table/binding按项目 SpacetimeDB skills 与文档同步检查绑定生成、migration.rs、private table 限制。
  5. 修改前补齐 docs/technical/ 中对应方案/根因;修改后同步更新。

关键经验:已登录打开网页也要主动 refresh 才能写登录埋点

常见误判:后端已经在 refresh cookie 续期时写每日登录埋点,就以为“打开网页”会触发埋点。

实际链路中,如果用户已经登录且本地 access token 还有效:

  1. ensureStoredAccessToken() 会直接返回已有 token。
  2. AuthGate 随后请求 /api/auth/me
  3. /api/auth/me 只校验/读取用户,不会 rotate refresh session。
  4. 因此后端 refresh/session 埋点不会触发。

若产品要求“已登录且 cookie 没过期时打开网页也记录登录埋点”,AuthGate 的 restore/hydrate 应主动调用 refreshStoredAccessToken(),再调用 getCurrentAuthUser()

每日登录埋点原则

  • 真实登录成功:在 refresh session / access token 创建成功后记录。
  • cookie refresh 续期:在 rotate refresh session 成功且新 access token 签发成功后记录。
  • 已登录打开网页:前端必须主动走 refresh 续期链路,不能只请求 /api/auth/me
  • login_method 对于 refresh 场景使用 refresh session 保存的 issued_by_provider
  • 埋点失败不阻断登录、续期、会话恢复或 token 返回,只记录 warning。
  • 任务中心读取不应作为登录埋点来源,避免后台查看/刷新任务中心污染登录数据。

测试与验证命令

按改动范围选择:

npm run test -- AuthGate.test.tsx
npm run typecheck
cd server-rs && cargo test -p api-server auth_session -- --nocapture
cd server-rs && cargo test -p api-server refresh_session_rotates_cookie_and_returns_new_access_token -- --nocapture
cd server-rs && cargo check -p api-server
cd server-rs && cargo check -p spacetime-client
cd server-rs && cargo check -p spacetime-module
npm run check:encoding
git diff --check

注意Vitest 0.34 不支持 Jest 的 --runInBand;不要把 --runInBand 加到 npm run test -- AuthGate.test.tsx 后面。

常见坑

  1. /api/auth/me 当作 refresh它只读当前 access token不会写 refresh 埋点。
  2. 只在后端 refresh handler 加埋点,但前端有有效 access token 时根本不调用 refresh。
  3. ensureStoredAccessToken() 有 token 时会直接返回;需要强制 refresh 时应使用 refreshStoredAccessToken()
  4. 在埋点 helper 中返回错误并阻断登录/续期,会破坏认证主链路。
  5. refresh 场景把 login_method 写死为 password会丢失手机/微信来源。
  6. 修改中文文件后忘记 npm run check:encoding
  7. cargo fmt -p api-server 或前端测试可能让 .env.local.gitignore 出现非业务改动;提交前用 git status --short 检查并撤回无关敏感/环境文件。

参考资料

  • references/session-restore-daily-login-tracking-2026-05-08.md:已登录且 cookie 未过期时打开网页未触发每日登录埋点的根因与修复案例。