fix(auth): preserve exact account IDs when decoding JWT claims

This commit is contained in:
2026-10-15 18:08:30 +08:00
parent f9193a3564
commit 60378fea9b
3 changed files with 104 additions and 1 deletions
+28
View File
@@ -0,0 +1,28 @@
import { describe, expect, it } from 'vitest'
import { decodeJwtClaims } from './jwt'
function token(payload: string) {
return `header.${Buffer.from(payload).toString('base64url')}.signature`
}
describe('JWT claim decoding', () => {
it.each(['2110664514823360515', '"2110664514823360515"'])('preserves the exact account ID encoded as %s', userId => {
const claims = decodeJwtClaims(token(`{"user_id":${userId},"app_code":"PLATFORM","exp":1792060000,"iat":1792058200}`))
expect(claims.user_id).toBe('2110664514823360515')
expect(claims.exp).toBe(1792060000)
expect(claims).toHaveProperty('iat', 1792058200)
})
it('retains safe numeric IDs and ordinary claims', () => {
expect(decodeJwtClaims(token('{"user_id":123,"username":"operator","roles":["ADMIN"],"exp":1}')))
.toEqual({ user_id: 123, username: 'operator', roles: ['ADMIN'], exp: 1 })
})
it.each(['', 'header..signature'])('rejects a missing payload: %s', value => {
expect(() => decodeJwtClaims(value)).toThrow('登录响应中的 accessToken 格式无效')
})
it.each(['header.%.signature', token('{"user_id":2110664514823360515,')])('rejects malformed encoding or JSON: %s', value => {
expect(() => decodeJwtClaims(value)).toThrow('登录响应中的 accessToken 无法解析')
})
})
+3 -1
View File
@@ -1,3 +1,5 @@
import { parseJsonWithSafeIntegers } from '@chongchong/shared'
export interface PlatformJwtClaims {
user_id?: string | number
username?: string
@@ -19,7 +21,7 @@ export function decodeJwtClaims(token: string): PlatformJwtClaims {
const payload = token.split('.')[1]
if (!payload) throw new Error('登录响应中的 accessToken 格式无效')
try {
return JSON.parse(decodeBase64Url(payload)) as PlatformJwtClaims
return parseJsonWithSafeIntegers(decodeBase64Url(payload)) as PlatformJwtClaims
} catch {
throw new Error('登录响应中的 accessToken 无法解析')
}