const EXACT_INTEGER_CLAIMS = [ 'user_id', 'userId', 'tenant_id', 'tenantId', 'operator_tenant_id', 'membership_id', 'overseas_warehouse_id', 'domestic_warehouse_id', 'actor_user_id', 'actor_membership_id' ] function decodeBase64Url(value) { const normalized = value.replace(/-/g, '+').replace(/_/g, '/') const padded = normalized.padEnd(Math.ceil(normalized.length / 4) * 4, '=') if (typeof atob === 'function') return decodeURIComponent(Array.from(atob(padded), (char) => `%${char.charCodeAt(0).toString(16).padStart(2, '0')}`).join('')) throw new Error('当前运行环境无法解析登录令牌') } function restoreExactIntegerClaims(payload, claims) { for (const key of EXACT_INTEGER_CLAIMS) { const match = payload.match(new RegExp(`"${key}"\\s*:\\s*(-?\\d+)`)) if (match) claims[key] = match[1] } return claims } export function decodeAccessToken(token) { const payloadPart = String(token || '').split('.')[1] if (!payloadPart) throw new Error('登录响应中的 accessToken 格式无效') try { const payload = decodeBase64Url(payloadPart) return restoreExactIntegerClaims(payload, JSON.parse(payload)) } catch (error) { if (error.message === '当前运行环境无法解析登录令牌') throw error throw new Error('登录响应中的 accessToken 无法解析') } }