web/src/utils/auth.ts
@@ -75,6 +75,50 @@
  return !!(token && userInfo)
}
/**
 * 解析并判断JWT是否过期
 * 规则:若token为空或无法解析exp,视为过期;exp单位为秒
 */
export function isTokenExpired(token?: string | null): boolean {
  if (!token) return true
  try {
    const parts = token.split('.')
    if (parts.length !== 3) return true
    const payloadJson = JSON.parse(decodeBase64Url(parts[1]))
    const exp = payloadJson?.exp
    if (!exp || typeof exp !== 'number') return true
    const now = Math.floor(Date.now() / 1000)
    return exp <= now
  } catch (e) {
    console.error('解析JWT失败:', e)
    return true
  }
}
/**
 * Base64Url 解码
 */
function decodeBase64Url(input: string): string {
  // 替换URL安全字符并补齐'='
  let base64 = input.replace(/-/g, '+').replace(/_/g, '/')
  const pad = base64.length % 4
  if (pad) {
    base64 += '='.repeat(4 - pad)
  }
  const decoded = atob(base64)
  // 处理UTF-8
  try {
    return decodeURIComponent(
      decoded
        .split('')
        .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
        .join('')
    )
  } catch {
    return decoded
  }
}
// 清除所有认证数据
export function clearAuth(): void {
  removeToken()