/** * 宿主(如 CC)嵌入 /embed-demo 时的 SSO 查询参数解析。 * 例:/embed-demo?login_type=api_key&api_key=chj_xxx * /embed-demo?type=api_key&key=chj_xxx * /embed-demo?login_type=password&customer_id=CUST_001&password=*** */ export type EmbedSsoLoginType = "password" | "api_key"; export type EmbedSsoParams = | { mode: "api_key"; apiKey: string } | { mode: "password"; customerId: string; password: string } | { mode: "none" }; const SENSITIVE_QUERY_KEYS = [ "login_type", "type", "lt", "api_key", "key", "token", "password", "pwd", "customer_id", "customerId", ] as const; function firstParam( params: URLSearchParams, keys: readonly string[], ): string { for (const k of keys) { const v = params.get(k)?.trim(); if (v) return v; } return ""; } function resolveLoginType(params: URLSearchParams): EmbedSsoLoginType | null { const raw = firstParam(params, ["login_type", "type", "lt"]).toLowerCase(); if (!raw) { // 有 key 无 type 时默认按 API Key if (firstParam(params, ["api_key", "key", "token"])) return "api_key"; if ( firstParam(params, ["customer_id", "customerId"]) && firstParam(params, ["password", "pwd"]) ) { return "password"; } return null; } if (raw === "api_key" || raw === "apikey" || raw === "key") return "api_key"; if (raw === "password" || raw === "pwd" || raw === "account") return "password"; return null; } /** 从 URLSearchParams 解析宿主直传凭证 */ export function parseEmbedSsoParams(params: URLSearchParams): EmbedSsoParams { const loginType = resolveLoginType(params); if (loginType === "api_key") { const apiKey = firstParam(params, ["api_key", "key", "token"]); if (!apiKey) return { mode: "none" }; return { mode: "api_key", apiKey }; } if (loginType === "password") { const customerId = firstParam(params, ["customer_id", "customerId"]); const password = firstParam(params, ["password", "pwd"]); if (!customerId || !password) return { mode: "none" }; return { mode: "password", customerId, password }; } return { mode: "none" }; } /** 登录成功后从地址栏去掉敏感参数,避免 Key 留在历史记录 */ export function stripEmbedSsoQueryFromUrl(): void { if (typeof window === "undefined") return; const url = new URL(window.location.href); let changed = false; for (const key of SENSITIVE_QUERY_KEYS) { if (url.searchParams.has(key)) { url.searchParams.delete(key); changed = true; } } if (!changed) return; const next = `${url.pathname}${url.search}${url.hash}`; window.history.replaceState(window.history.state, "", next); } /** 是否宿主嵌入精简壳(隐藏退出等) */ export function isEmbedHostedShell(params: URLSearchParams): boolean { const flag = firstParam(params, ["embed", "hosted", "from_cc", "from_host"]); if (flag === "1" || flag === "true" || flag === "yes") return true; // 带 SSO 凭证进入亦视为宿主托管 return parseEmbedSsoParams(params).mode !== "none"; }