// shared/lib/auth/jwt-edge.ts — V2 Edge Runtime JWT 验证(步骤 1a 新增) // 使用 Web Crypto API(Edge Runtime 兼容),3 参数强制校验 iss 匹配 import type { SessionPayloadV2 } from './types-v2' /** Base64url 解码为 Uint8Array */ function base64urlToBytes(str: string): Uint8Array { const base64 = str.replace(/-/g, '+').replace(/_/g, '/') const padding = '='.repeat((4 - (base64.length % 4)) % 4) const binary = atob(base64 + padding) const bytes = new Uint8Array(binary.length) for (let i = 0; i < binary.length; i++) { bytes[i] = binary.charCodeAt(i) } return bytes } /** 将 ArrayBuffer 转为 hex 字符串 */ function bufferToHex(buffer: ArrayBuffer): string { return Array.from(new Uint8Array(buffer)) .map(b => b.toString(16).padStart(2, '0')) .join('') } /** 验证 JWT(Edge Runtime),3 参数。expectedIss = '*' 时跳过 iss 校验(迁移模式) */ export async function verifyJwtEdge( token: string, secret: string, expectedIss: string ): Promise { try { const parts = token.split('.') if (parts.length !== 3) return null // 解码 payload const payload = JSON.parse(atob(parts[1].replace(/-/g, '+').replace(/_/g, '/'))) as SessionPayloadV2 // 过期检查 if (payload.exp && payload.exp * 1000 < Date.now()) return null // iss 校验(* 为迁移模式,跳过校验,兼容旧 token 不含 iss) if (expectedIss !== '*' && payload.iss !== expectedIss) return null // 验签(HMAC-SHA256) const encoder = new TextEncoder() const key = await crypto.subtle.importKey( 'raw', encoder.encode(secret), { name: 'HMAC', hash: 'SHA-256' }, false, ['verify'] ) const data = encoder.encode(`${parts[0]}.${parts[1]}`) const signature = base64urlToBytes(parts[2]) // eslint-disable-next-line @typescript-eslint/no-explicit-any const valid = await crypto.subtle.verify('HMAC', key, signature as any, data) return valid ? payload : null } catch { return null } }