## Context JWT 载荷为 `{ sub, tenantCode, username, ver, sid }`;`RequestContext` 由 token 派生,`resolveAuth`/`buildContext`/`getMenus` 在**当前租户**内解析角色与 `isSuper`;`checkUserActive` 在**当前租户**内查用户。多租户隔离使平台超管(`touyun`)看不到 `demo` 租户数据。动机见 proposal.md - Why。 ## Goals / Non-Goals **Goals:** - 平台超管切入任意租户,数据按目标租户过滤、权限超管绕过、审计归属保留真实超管。 **Non-Goals:** - 不做普通用户/业务租户管理员的跨租户切换。 - 不做「切回上一个租户」的历史记录(重新选择即可)。 ## Decisions ### D1 — 身份保留 + `super` 标志 JWT 增加 `super?: boolean`(仅切换接口签发 true)。`sub` 始终是平台超管真实 userId,`tenantCode` 为切入租户。切回 = 再次切换(切到 `touyun`)。 - **为什么不用「冒充目标租户管理员」**:会丢失超管真实身份,切回需重新登录,审计归属也错。 ### D2 — `POST /auth/switch-tenant` 仅登录态;校验 `isPlatformSuperAdmin(userId)`(查 `touyun` 的 `user_role` 是否含 `super_admin`)+ 目标租户存在且 enabled;签发 `super:true` 新 token(沿用超管 `ver`,新 `sid`);记审计 `auth/switch-tenant`。 ### D3 — `isSuper` 解析改为「平台租户为准」 `isPlatformSuperAdmin(userId)` = 平台租户 `user_role` 含 `super_admin`。`resolveAuth`/`buildContext`/`getMenus` 的 `isSuper = 当前租户含 super_admin || isPlatformSuperAdmin(userId)`。`checkUserActive` 对 `super` token 在**平台租户**查用户(因超管 userId 在 `touyun` 而非目标租户)。 ### D4 — 前端顶栏切换 `permissionStore.super` 为真时显示「切换租户」下拉(列 `GET /tenants`);切换后 `auth` store 换 token、`reset` 菜单/字典/权限/页签,刷新进入目标租户上下文。 ## Risks / Trade-offs - **[super 标志被篡改]** → JWT 签名防篡改,且仅 switch 接口签发 `super:true`。 - **[切换后超管自身待改密]** → super token 仍走 `checkUserActive`,超管待改密时需先改密(可接受)。 ## Migration Plan 无数据迁移;纯后端 + 前端。回滚即撤销。 ## Open Questions 无。