问题
后端认证模块已在 PR #75 落地,鉴权中间件的白名单只放行 /auth/* 与文档、健康检查,其余接口一律要求有效的 access token。前端目前没有任何会话概念:没有模块持有令牌,shared/api 的 registerApiAccessTokenProvider 至今无人注册,因此所有需要鉴权的请求都会被拒。
PR #147 提供了一份完整的会话层实现,但作者没有时间继续推进,本 issue 接手该实现并补齐评审指出的缺口。
目标
提供一个持有登录会话的模块,向上给界面暴露状态与操作,向下给 shared/api 提供 access token。本 issue 不含任何界面。
范围
包含:
entities/user:用户实体与八个端点的接口契约,字段映射后端 UserOut 与 TokenResponse
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 失效。
resolveAuthMode、AuthModeProvider、createLocalUserApis 属于装配职责,边界归 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 不可用时仍可完成登录,仅退化为不跨刷新保持。
单元测试覆盖上述四条,以及并发续期只发一次请求。
问题
后端认证模块已在 PR #75 落地,鉴权中间件的白名单只放行
/auth/*与文档、健康检查,其余接口一律要求有效的 access token。前端目前没有任何会话概念:没有模块持有令牌,shared/api的registerApiAccessTokenProvider至今无人注册,因此所有需要鉴权的请求都会被拒。PR #147 提供了一份完整的会话层实现,但作者没有时间继续推进,本 issue 接手该实现并补齐评审指出的缺口。
目标
提供一个持有登录会话的模块,向上给界面暴露状态与操作,向下给
shared/api提供 access token。本 issue 不含任何界面。范围
包含:
entities/user:用户实体与八个端点的接口契约,字段映射后端UserOut与TokenResponsefeatures/auth-session:会话 Provider,三态为启动中、访客、已登录不包含:
entities/project的任何改动。ProjectPageQuery.ownerId这处遗留由 PR feat(project-create): add the project creation page #142 一并清理,本 issue 不碰该模块实现约束
code字段里,见middleware/auth.py的_biz_error。判断登录失效必须依据ApiError.code === 401,依据 HTTP 状态码会导致登录态永不过期。code=401的响应式处理,不能只依赖定时器。标签页被挂起时定时器不会准时触发,醒来后令牌已过期。收到 401 时先尝试续期并重放请求,续期失败再转访客。/auth/refresh会轮换 refresh token 并返回新的一份。必须监听storage事件在标签页之间同步登录、登出与续期结果,否则两个标签页同时打开时会互相使对方的 refresh token 失效。resolveAuthMode、AuthModeProvider、createLocalUserApis属于装配职责,边界归 feat: 统一前端路由、导航与真实依赖装配(Refs #70) #103。本模块保留本地开发适配器时,AuthModeProvider这类只做转发的空壳要去掉,启用本地适配器时界面上需有明确标识,避免误认为登录已打通。后端契约要点
/auth/logout在鉴权白名单内,请求体传refresh_token。user与/auth/me返回的用户对象,JSON 键名与类型一致,可共用一套映射。验收标准
code=401时触发续期并重放;续期失败后状态转访客且令牌被清除。