# 切角色 / 刷新令牌「掉登」已修 + 前端必改一项(原子保存 token) > 模块:admin 鉴权(hl-user-service)/ 管理后台 > 类型:后端 bug 修复(PR #4529 已合 dev-v3 + 测试服实测生效)+ **前端必改一项加固** > 日期:2026-06-28 ## 背景 / 修了什么(后端) 两个掉登 bug 已修: - **Bug1(切角色被登出)**:超管切到「房务」等角色后刷新页面报「刷新令牌无效或已过期」被踢回原角色。根因:切角色会轮转 refresh 令牌、使旧 refresh 立即失效,前端若没存住新 refresh 就被登出。 - 后端修复:**切角色不再轮转 refresh**(只换发带新角色的 access,refresh 复用、保持有效)。即使前端不改也不会再因切角色被登出。 - **Bug2(刷新偶发掉登)**:整页刷新偶发「刷新令牌无效或已过期」。根因:refresh 校验与续期非原子,并发刷新读到中间态。 - 后端修复:refresh 校验+续期改为 Redis 原子执行,并发刷新不再误判。 测试服实测:切角色后用原 refresh 刷新 200(不掉登);同一 refresh 并发 3 次刷新全 200;切「定制师/房务」回归全正常。 ## 前端必改(1 项加固) **切角色 `POST /admin/auth/switch-role` 与刷新 `POST /admin/auth/refresh` 的响应里,`token`(access) 与 `refreshToken` 要原子地一起保存**(两者同时落本地存储,避免只存其一),切角色后用响应里的新 `token` 调后续接口。 - 说明:后端每次 switch-role / refresh 都换发**新 access**并把旧 access 轮转出(access 白名单 last-issued-wins)。所以切角色/刷新后**必须改用响应里的新 access**,旧 access 会失效(这是既有设计,非本次改动)。本次修复保证的是 **refresh 不会因切角色失效**,刷新链路稳定。 ## 影响接口 - `POST /admin/auth/switch-role`(行为:refresh 不再轮转;响应结构不变) - `POST /admin/auth/refresh`(行为:校验+续期原子化;响应结构不变)