/** * 文件作用: * 为 SuperAgent 请求签发 Agent 可验证的短时 JWT。 * * 职责: * 1. 从 ai-center 登录用户信息提取之前 X-User-Id 对应的 userid,写入 JWT sub。 * 2. 用 query api 配置的密钥/私钥签名,算法与 Agent AUTH_* 对齐。 * * 不负责: * 1. 验证 ai-center 登录 token。 * 2. 把 X-User-Id 当作 Agent 身份。 */ 'use strict'; const crypto = require('crypto'); const DEFAULT_EXPIRES_IN_SECONDS = 3600; const SUPPORTED_ALGORITHMS = new Set(['HS256', 'RS256']); const toBase64Url = (value) => { const buffer = Buffer.isBuffer(value) ? value : Buffer.from(value); return buffer.toString('base64url'); }; const encodeJson = (value) => toBase64Url(JSON.stringify(value)); const unwrapUserInfo = (userInfo) => { if (!userInfo || typeof userInfo !== 'object') return null; if (userInfo.AIUserInfo && typeof userInfo.AIUserInfo === 'object') { return userInfo.AIUserInfo; } if (userInfo.userInfo && typeof userInfo.userInfo === 'object') { return userInfo.userInfo; } if (userInfo.user && typeof userInfo.user === 'object') { return userInfo.user; } return userInfo; }; const firstNonEmpty = (...values) => { for (const value of values) { if (value === undefined || value === null) continue; const text = String(value).trim(); if (text) return text; } return ''; }; const createConfigError = (message) => { const error = new Error(message); error.status = 503; return error; }; const createRequestError = (message, status = 401) => { const error = new Error(message); error.status = status; return error; }; const normalizePem = (value) => String(value || '').replace(/\\n/g, '\n').trim(); const resolveJwtConfig = (rawConfig = {}) => { const algorithm = String(rawConfig.algorithm || 'HS256').trim().toUpperCase(); const expiresInSeconds = Number(rawConfig.expiresInSeconds || DEFAULT_EXPIRES_IN_SECONDS); return { algorithm, secret: String(rawConfig.secret || '').trim(), privateKey: normalizePem(rawConfig.privateKey), issuer: String(rawConfig.issuer || '').trim(), audience: String(rawConfig.audience || '').trim(), expiresInSeconds: Number.isFinite(expiresInSeconds) && expiresInSeconds > 0 ? Math.floor(expiresInSeconds) : DEFAULT_EXPIRES_IN_SECONDS, }; }; const signJwt = (payload, config) => { if (!SUPPORTED_ALGORITHMS.has(config.algorithm)) { throw createConfigError(`不支持的 Agent JWT 算法:${config.algorithm}`); } const header = { alg: config.algorithm, typ: 'JWT' }; const signingInput = `${encodeJson(header)}.${encodeJson(payload)}`; if (config.algorithm === 'HS256') { if (!config.secret) { throw createConfigError('未配置 Agent JWT 签名密钥'); } const signature = crypto .createHmac('sha256', config.secret) .update(signingInput) .digest(); return `${signingInput}.${toBase64Url(signature)}`; } if (!config.privateKey) { throw createConfigError('未配置 Agent JWT 签名私钥'); } const signature = crypto.createSign('RSA-SHA256').update(signingInput).sign(config.privateKey); return `${signingInput}.${toBase64Url(signature)}`; }; const resolveAgentUserId = (userInfo) => { const identity = unwrapUserInfo(userInfo); if (!identity) return ''; return firstNonEmpty( identity.localUserId, identity.id, identity.userId, identity.userid, identity.user_id, identity.uid, identity.pepUserId, identity.pep_user_id, identity.pepId, identity.pep_id, ); }; const issueAgentAccessToken = ({ userInfo, config, now = Date.now() } = {}) => { const jwtConfig = resolveJwtConfig(config); const sub = resolveAgentUserId(userInfo); if (!sub) { throw createRequestError('认证用户信息无效'); } const issuedAt = Math.floor(now / 1000); const expiresAt = issuedAt + jwtConfig.expiresInSeconds; const payload = { sub, iat: issuedAt, exp: expiresAt, }; if (jwtConfig.issuer) payload.iss = jwtConfig.issuer; if (jwtConfig.audience) payload.aud = jwtConfig.audience; return { token: signJwt(payload, jwtConfig), token_type: 'Bearer', expires_in: jwtConfig.expiresInSeconds, expires_at: expiresAt, sub, }; }; module.exports = { DEFAULT_EXPIRES_IN_SECONDS, resolveAgentUserId, resolveJwtConfig, issueAgentAccessToken, };