# Web 登录与页面恢复 ## 路由规则 - `/login` 为独立登录页,不挂载家庭或维护布局。家庭端默认手机号验证码登录,“账号登录”保留已有 OIDC 账号入口。 - 根地址的全部家庭栏目、`/maintenance`、`/onboarding/setup` 和 `/onboarding/devices` 均先校验身份。未登录时使用 `replaceState` 跳转 `/login?returnTo=...`。 - 校验中只显示加载状态;家庭业务接口与布局在认证完成后才挂载。`designPreview=1` 同样受保护。 - 成功登录后恢复目标页面的路径、查询参数和锚点。没有显式目标时使用当前标签页最近访问的业务页,再回退首页。 - 已登录用户访问登录页直接返回目标业务页。退出或接口返回 401 时卸载业务内容,并保留当时的页面地址供重新登录。 - 浏览器前进、后退或恢复缓存文档时执行相应的路由或身份校验。403 保持为权限错误,不触发全局退出。 返回地址只接受当前源的已知业务路由,拒绝外部地址、协议相对地址、反斜杠、登录页和回调页,避免开放重定向及登录循环。返回地址仅决定页面位置,服务端继续校验资源权限。 ## 认证方式 `AuthProvider` 统一管理整站会话。家庭端可以使用 HttpOnly 账号 Cookie 或 OIDC;维护端仍需有效 OIDC 令牌和服务端维护角色。Cookie 不授予维护权限。 短信登录通过 `/api/v1/web/login/session`、`/api/v1/web/login/sms/send` 和 `/api/v1/web/login/sms/verify` 完成。账号 Cookie 恢复后仍需 `/api/v1/me` 取得有效账号和权限。发送失败、验证码错误和网络异常会显示在登录页。配置说明见 [家庭端短信登录](customer-sms-login.md)。 OIDC 使用授权码与 PKCE,登录目标存入 OIDC 事务状态。`/auth/callback` 只交换一次授权码,验证返回地址后恢复业务路由。令牌过期、续期失败和业务请求 401 会清理本地认证状态。 ## 设备绑定 `/onboarding/entry#token=...&verifier=...` 先兑换一次性入口并删除地址中的凭据,再进入统一登录流程。返回目标固定为 `/onboarding/setup`,一次性凭据不写入返回参数或页面历史记录缓存。 来自有效匿名设备设置会话的短信登录继续使用设备所属组织的原有注册规则,表单位于独立登录页。已有短信账号或 OIDC 账号登录后,通过 `/api/v1/web/setup/auth-link` 关联原设置会话;此接口同时核验同源请求、设置 Cookie、设置 CSRF 和账号身份。关联后旋转设置 Cookie,继续选择使用者和设备按键确认。 ## 自动化验证 ```powershell npm run build --prefix web $env:PLAYWRIGHT_REQUIRE_FROM = "$env:USERPROFILE/.cache/codex-runtimes/codex-primary-runtime/dependencies/node/node_modules/playwright/package.json" node test/e2e/customer-sms-login.mjs node test/e2e/login-routing.mjs node test/e2e/memory-workspace.mjs powershell.exe -NoProfile -ExecutionPolicy Bypass -Command "& './scripts/test-onboarding-integration.ps1' -Packages onboarding,httpapi -VerboseTests -OutputDirectory '.tmp-login-routing'" ``` 浏览器脚本运行真实 React 页面、路由和客户端,短信、账号与 OIDC 响应为测试替身,不发送真实短信。覆盖 11 个家庭栏目拦截、深链恢复、重载、退出后回退、401、缓存文档恢复、返回地址验证、OIDC 回调去重和设备入口继续绑定。数据库脚本使用临时真实数据库,包含短信账号关联设置会话及身份、同源、CSRF 的拒绝用例。 截图及结果分别位于 `.design-evidence/customer-sms-login/`、`.design-evidence/login-routing/` 和 `.design-evidence/call-memory/`。真实短信送达及部署环境的 OIDC/HTTPS 配置需在对应环境验证。