- access token 是 15 分钟的 JWT,走 Authorization: Bearer;refresh token 7 天,每次换都轮换 - 退出登录、改密码、禁用账号仍然立刻生效:每个请求核对 Redis 会话和库里新加的 user.token_version - 在服务器后台改密码 / 禁用,机房那边登着的也会一起下线(原来两边 Redis 分开,管不到) - WebSocket 握手借子协议带 token;JWT 密钥存在本站 Redis,部署不用加配置 - 去掉 COOKIE_SECURE;上线后所有人要重新登录一次 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
4be569d978
commit
793848b06f
31 files changed
+4639
-333
No files matched your search
@@ -5,6 +5,33 @@ export const loginRequestSchema = z.object({
|
||||
password: z.string().min(1).max(1024),
|
||||
})
|
||||
|
||||
/** 换 access token、退出登录都拿 refresh token 当凭证 */
|
||||
export const refreshTokenRequestSchema = z.object({
|
||||
refreshToken: z.string().min(1).max(512),
|
||||
})
|
||||
|
||||
/**
|
||||
* WebSocket 握手带 access token 用的子协议名。浏览器的 `new WebSocket()` 设不了请求头,
|
||||
* 前端传 `[WS_AUTH_PROTOCOL, token]` 两个子协议,服务端回第一个 —— 必须回一个前端
|
||||
* 传过的,否则 Chrome 判握手失败。不放 URL 查询参数:URL 会原样进反代的访问日志。
|
||||
*/
|
||||
export const WS_AUTH_PROTOCOL = "oj2.bearer"
|
||||
|
||||
/**
|
||||
* 登录、换 token 的出参。
|
||||
*
|
||||
* `expiresIn` 是秒数而不是到期时刻:机房电脑的时钟不一定准,前端拿自己的时钟加上它
|
||||
* 算到期,才不会因为差了几分钟一直以为 token 已过期。
|
||||
*
|
||||
* `refreshToken` 为 null 只出现在换 token 的宽限期里(同一张 refresh token 刚被别的
|
||||
* 标签页换掉),这时沿用本地已经存着的那张,见 auth/session.ts 的 refreshTokens。
|
||||
*/
|
||||
export interface AuthTokens {
|
||||
accessToken: string
|
||||
refreshToken: string | null
|
||||
expiresIn: number
|
||||
}
|
||||
|
||||
export const sessionUserSchema = z.object({
|
||||
id: z.number().int(),
|
||||
username: z.string(),
|
||||
@@ -29,5 +56,6 @@ export const userProfileSchema = z.object({
|
||||
})
|
||||
|
||||
export type LoginRequest = z.input<typeof loginRequestSchema>
|
||||
export type RefreshTokenRequest = z.input<typeof refreshTokenRequestSchema>
|
||||
export type SessionUser = z.infer<typeof sessionUserSchema>
|
||||
export type UserProfile = z.infer<typeof userProfileSchema>
|
||||
Reference in new issue
Block a user