|
|
/**
|
|
|
* 宿主(如 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";
|
|
|
}
|