Files
social-app/docs/plans/2026-03-18-auth-global-rewrite-design.md
T
qzl b34697660d feat: 实现 Auth 全局状态机与 401 统一处理机制
- 新增 AuthSessionInvalidated 事件处理 token 失效场景
- ApiInterceptor 新增 authFailureCallback 单飞机制
- AuthBloc 区分 manual logout 与 auto expiry 语义
- 新增 startup recovery fallback 防止启动卡死

feat: 重构 Calendar DayWeek 视图事件布局引擎

- 新增 DayEventLayoutEngine 解耦事件计算与渲染
- 新增 DayTimelineMetrics 统一时间轴常量
- 新增 DayViewScale 支持捏合缩放

feat: 新增 Settings 页面共享 UI 组件

- 新增 BackTitlePageHeader 统一页面 header
- 新增 DetailHeaderActionMenu 统一操作菜单
- 新增 DestructiveActionSheet 统一删除确认
- 新增 AppToggleSwitch 统一开关组件

feat: Chat UI Schema 支持导航操作

- 支持 navigation 类型 action 触发内部路由跳转
- 新增路径验证与参数处理

chore: 更新相关测试覆盖 auth 失效路径
2026-03-18 13:35:25 +08:00

3.4 KiB
Raw Blame History

Auth 全局模块重写设计(跨端并存、同端互斥)

1. 目标

  • 彻底消除 Auth 分裂状态:token 状态与 AuthBloc 状态必须单一真相源。
  • 会话策略升级为:
    • 同账号允许跨端并存:mobile + web + desktop
    • 同账号同端互斥:同端新登录会挤下线旧设备
  • 保证任何 401 链路在刷新失败后都能统一收敛为“未登录 + 清理本地 + 路由回到登录页”。
  • 消除设备差异导致的不一致行为(部分机型“假登录”或“卡死页”)。

2. 边界与约束

  • 仅重写 apps/** 的 Auth 客户端架构与规则,不改后端协议语义。
  • 保持现有登录/注册 UI 路由入口,避免用户操作路径变化。
  • 认证属于高风险域,重写必须覆盖:
    • 启动恢复
    • 运行时 token 过期
    • 并发 401
    • 手动登出与自动过期登出的差异行为

3. 核心架构

3.1 单一真相源(Single Source of Truth

  • AuthBloc 成为唯一认证状态源。
  • ApiInterceptor 只负责协议级拦截与刷新,不直接做路由跳转。
  • 401 刷新失败时,ApiInterceptor -> ApiClient callback -> AuthBloc(AuthSessionInvalidated)
  • 路由守卫只看 AuthBloc 状态,不再做隐式 token 判定。

3.2 会话状态机

  • AuthInitial
  • AuthLoading(启动恢复/会话检查)
  • AuthAuthenticated(user)
  • AuthUnauthenticated(reason)

reason 取值:

  • signedOut
  • expired
  • startupRecoveryFailed

3.3 登出语义分离

  • 手动登出:deleteSession()
    • 尝试调用后端注销
    • 最终清本地
  • 自动过期:clearSessionLocalOnly()
    • 仅清本地
    • 不调用后端注销接口

3.4 并发与抖动控制

  • ApiInterceptor 继续使用 refresh singleflight。
  • 新增 auth failure singleflight:多并发 401 刷新失败,只触发一次全局会话失效事件。

3.5 设备差异治理

  • 启动时 token 读取异常必须兜底:进入 AuthUnauthenticated(startupRecoveryFailed),避免卡死在 Boot。
  • FlutterSecureStorage 显式平台配置:
    • Android 使用 encryptedSharedPreferences
    • iOS 指定 keychain accessibility(保证行为稳定)

4. 数据流

4.1 冷启动

  1. main 触发 AuthStarted
  2. AuthBloc 读取 refresh token
  3. 有 refresh token -> 刷新会话 -> 成功进入 AuthAuthenticated
  4. 无 token 或异常 -> AuthUnauthenticated(startupRecoveryFailed)

4.2 运行时 API 请求

  1. 请求携带 access token
  2. 401 -> 触发 refresh
  3. refresh 成功 -> 自动重试原请求
  4. refresh 失败 -> 触发一次全局 auth failure
  5. AuthBloc 收到 AuthSessionInvalidated(expired) -> 清本地 -> AuthUnauthenticated(expired)
  6. Router 根据状态回登录页

5. 测试策略

  • AuthBloc
    • 启动读取 refresh token 异常兜底
    • session invalidated 事件导致统一未登录
  • ApiInterceptor
    • 并发 401 refresh 失败仅触发一次 auth failure
  • AuthRepository
    • 手动登出 vs 自动过期清理行为差异

6. 迁移计划

  • 先引入新事件/新回调/新状态原因,不改 UI 交互。
  • 再改路由守卫识别未登录原因。
  • 最后补齐 apps/AGENTS.md Auth 强约束,防止后续回归为“各处乱写”。

7. 风险与回滚

  • 风险:回调链路接错导致频繁误登出。
  • 规避:并发 singleflight + 精确触发条件(仅 401 refresh 失败)。
  • 回滚:保留旧事件兼容层,出现异常可快速退回旧路由判定。