Skip to content

feat(auth): split auth session module — user entity + session management - #144

Closed
xyh202131 wants to merge 1 commit into
1024XEngineer:mainfrom
xyh202131:split/auth-session
Closed

feat(auth): split auth session module — user entity + session management#144
xyh202131 wants to merge 1 commit into
1024XEngineer:mainfrom
xyh202131:split/auth-session

Conversation

@xyh202131

@xyh202131 xyh202131 commented Aug 6, 2026

Copy link
Copy Markdown

变更范围

拆分登录与认证会话模块到独立分支,包含两个子模块:

entities/user —— 用户实体契约

  • index.tsUserAuthTokensUserApis 类型定义(sendCode / register / login / loginByCode / refresh / logout / me / changePassword 共 8 个方法)
  • api.tscreateUserApis 后端适配器,蛇形命名 → 驼峰命名映射,支持注入 ApiClient

features/auth-session —— 认证会话管理

  • index.tsxAuthSessionProvider(三态:booting → guest | authenticated)、useAuthSession() hook、ProtectedRoute 路由守卫(含安全 returnTo 校验)、resolveAuthMode() 开发/生产适配、createLocalUserApis() 本地开发适配器
  • session-storage.ts — refresh token 的 localStorage 持久化与降级处理

模块依赖

测试覆盖(14 个测试用例)

  • StrictMode 下启动 token 旋转只执行一次
  • 登录后 access token 存内存、refresh token 写 localStorage
  • 卸载时自动注销 access token provider
  • 启动恢复失败回退到 guest
  • 注销后 stale 恢复结果不覆盖当前会话
  • stale 启动失败不覆盖更新的登录态
  • 登出先清本地再请求后端
  • 密码修改后清除会话
  • JWT 过期前 60 秒自动刷新
  • 并发 refresh 请求去重
  • resolveAuthMode 开发/生产行为
  • createLocalUserApis 不泄露密码到存储
  • ProtectedRoute 安全 returnTo 校验
  • localStorage 不可用时的降级

@vercel

vercel Bot commented Aug 6, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
windup Ready Ready Preview Aug 6, 2026 9:43am

@fennoai fennoai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Found two auth-session lifecycle regressions: the access-token provider is never unregistered on unmount, and the startup refresh path can still run twice across StrictMode remounts.

[apis],
)

useEffect(() => registerApiAccessTokenProvider(() => accessTokenRef.current), [])

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High: this effect ignores the unregister callback returned by registerApiAccessTokenProvider. The provider stays on the global stack after unmount, so getApiAccessToken() can keep returning a stale token and later mounts/tests will inherit leaked state.

useEffect(() => {
let active = true

if (!bootstrapPromiseRef.current) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

High: the bootstrap refresh is cached only inside this component instance. In React StrictMode the provider is mounted, unmounted, and mounted again, so the initial rotateTokens() call can fire twice for the same persisted refresh token and defeat the intended single-refresh behavior.

…gement

Split the auth session module from the main codebase:

entities/user:
- User, AuthTokens, UserApis type definitions
- createUserApis backend adapter (snake_case -> camelCase mapping)
- Supports ApiClient injection for testability

features/auth-session:
- AuthSessionProvider: three-state session (booting -> guest | authenticated)
- useAuthSession() hook for consuming auth context
- ProtectedRoute: route guard with safe returnTo validation
- resolveAuthMode(): local dev by default, forces backend in production
- createLocalUserApis(): browser-only dev adapter (no password verification)
- session-storage: refresh token localStorage persistence with graceful degradation

Tests: 14 test cases covering session lifecycle, token rotation, StrictMode
dedup, stale request handling, JWT refresh scheduling, local dev adapter,
and route protection.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant