fix(登录): 两个标签页同时换 token 时,学生可能过一刻钟被莫名踢下线
Deploy / deploy (push) Canceled after 0s

refresh token 轮换原来是「读出来、查库、写回去」,两个标签页同时换会各自轮换出一张,
后写的冲掉先写的;浏览器里留下的若是被冲掉那张,下次换就被拒。机房走 http 用不了
navigator.locks,前端没法让标签页排队。

- 轮换改成比对再写入(Lua),抢输的重读后走宽限期
- 宽限期里回的是当前那张 refresh token,不再回 null,几个标签页最后落到同一张上
- 响应丢了、前端拿旧的重试,也由同一支接住

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
xuyueandClaude Opus 5.5 committed 2026-10-20 19:27:08 +08:00
1 parent 793848b06f
commit 13843c79a0
3 files changed
+108 -66

No files matched your search

+3 -3
View File
@@ -23,12 +23,12 @@ export const WS_AUTH_PROTOCOL = "oj2.bearer"
* `expiresIn` 是秒数而不是到期时刻:机房电脑的时钟不一定准,前端拿自己的时钟加上它
* 算到期,才不会因为差了几分钟一直以为 token 已过期。
*
* `refreshToken` 为 null 只出现在换 token 的宽限期里(同一张 refresh token 刚被别的
* 标签页换掉),这时沿用本地已经存着的那张,见 auth/session.ts 的 refreshTokens。
* 换 token 时 `refreshToken` 一般是新轮换出来的一张;同一张刚被别的标签页换掉的话,
* 回的是那个标签页拿到的那张,见 auth/session.ts 的 REFRESH_GRACE_MS。
*/
export interface AuthTokens {
accessToken: string
refreshToken: string | null
refreshToken: string
expiresIn: number
}