Skip to content

feat: 实现前端认证会话层(Refs #157) #158

Description

@huyanxius

问题

后端认证模块已在 PR #75 落地,鉴权中间件的白名单只放行 /auth/* 与文档、健康检查,其余接口一律要求有效的 access token。前端目前没有任何会话概念:没有模块持有令牌,shared/apiregisterApiAccessTokenProvider 至今无人注册,因此所有需要鉴权的请求都会被拒。

PR #147 提供了一份完整的会话层实现,但作者没有时间继续推进,本 issue 接手该实现并补齐评审指出的缺口。

目标

提供一个持有登录会话的模块,向上给界面暴露状态与操作,向下给 shared/api 提供 access token。本 issue 不含任何界面。

范围

包含:

  • entities/user:用户实体与八个端点的接口契约,字段映射后端 UserOutTokenResponse
  • features/auth-session:会话 Provider,三态为启动中、访客、已登录
  • access token 只存内存,refresh token 持久化到 localStorage,存储不可用时降级为仅内存会话
  • 启动时用持久化的 refresh token 恢复会话,失败转访客
  • access token 过期前静默续期,并发续期请求去重
  • 注册 access token provider,模块卸载时撤销

不包含:

实现约束

  • 起点是 PR feat(auth): add auth session module with user entity and session management #147 的实现,可直接复用,PR 正文需注明来源与作者。
  • 后端的 401 与 429 都以 HTTP 200 返回,业务码在响应体的 code 字段里,见 middleware/auth.py_biz_error。判断登录失效必须依据 ApiError.code === 401,依据 HTTP 状态码会导致登录态永不过期。
  • 必须提供对 code=401 的响应式处理,不能只依赖定时器。标签页被挂起时定时器不会准时触发,醒来后令牌已过期。收到 401 时先尝试续期并重放请求,续期失败再转访客。
  • /auth/refresh 会轮换 refresh token 并返回新的一份。必须监听 storage 事件在标签页之间同步登录、登出与续期结果,否则两个标签页同时打开时会互相使对方的 refresh token 失效。
  • resolveAuthModeAuthModeProvidercreateLocalUserApis 属于装配职责,边界归 feat: 统一前端路由、导航与真实依赖装配(Refs #70) #103。本模块保留本地开发适配器时,AuthModeProvider 这类只做转发的空壳要去掉,启用本地适配器时界面上需有明确标识,避免误认为登录已打通。
  • 用户状态遇到 0 与 1 之外的取值时按正常处理并保留原值,不要让整个登录失败。
  • 字段映射统一显式书写,不依赖驼峰与蛇形恰好同形。

后端契约要点

  • access token 有效期 15 分钟,refresh token 7 天。
  • /auth/logout 在鉴权白名单内,请求体传 refresh_token
  • 登录返回的 user/auth/me 返回的用户对象,JSON 键名与类型一致,可共用一套映射。

验收标准

  • 启动时若存在有效的 refresh token,恢复为已登录;无效或缺失则为访客。
  • 任一请求返回 code=401 时触发续期并重放;续期失败后状态转访客且令牌被清除。
  • 同一浏览器的两个标签页,其一登出后另一个同步转为访客;其一续期后另一个不会因 refresh token 失效而掉线。
  • localStorage 不可用时仍可完成登录,仅退化为不跨刷新保持。
  • 单元测试覆盖上述四条,以及并发续期只发一次请求。

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions