status: complete created: 2026-08-04 complexity: 中等
默认租户的超级管理员切换到其它启用租户后,前端重新加载用户信息时持续收到“用户不存在”,权限路由守卫反复替换当前路由,导致接口无限重试和错误弹窗;浏览器刷新后仍使用原 Token,问题无法自行恢复。
本变更目标:
LoginUser,避免用户名在目标租户下无法重新定位用户。SysTenantServiceImpl#switchTenant 使用 Session 中的 userId 调用 loadUserByUserId(userId, targetTenantId),超级管理员可按设计进入任意启用租户。AuthController#getUserInfo 却使用 username + currentTenantId 调用 loadUserByUsername。SysUserMapper.xml#selectByUsernameForLogin 要求用户主租户为目标租户,或存在目标租户的 sys_user_tenant 绑定。默认租户超级管理员无需该绑定,因此查询为空并抛出“用户不存在”。TenantSwitcher.vue 在切换成功后保留 Token、清空用户和菜单状态并跳转首页,触发权限守卫重新初始化。permission-guard.js 在用户信息初始化失败后仍执行 next({ ...to, replace: true })。userStore.userInfo 仍为空,新导航再次进入同一初始化分支,形成无限请求;刷新后持久化 Token 仍在,循环继续。/auth/userInfo 使用 Session 中的 userId、当前 tenantId 和 activeOrgId 重建用户信息。LoginUser。userId,不接受客户端传入用户标识。loadUserByUserId 继续通过 buildLoginUser 重建目标租户下的组织、角色、菜单/API 权限。GET /auth/userInfo 的内部刷新键从用户名改为已认证用户 ID。AuthController#getUserInfo 原刷新调用和权限守卫原失败分支即可;无数据回滚。userId 刷新、目标租户参数、Session 回写和登录元数据保留。git diff --check。AuthControllerTest 2/2 通过,覆盖稳定用户 ID 刷新、登录元数据保留、Session 回写和空 Session。auth-bootstrap-recovery.spec.js 2/2 通过,覆盖单次清理/跳转及登录页自重定向保护。