fix(auth): normalize external accessToken and preserve on empty yUser login
This commit is contained in:
1 parent
44d7304f8e
commit
1847eb9d6a
5 files changed
+53
-20
No files matched your search
@@ -0,0 +1,7 @@
|
||||
export function normalizeExternalAccessToken(value: unknown): string {
|
||||
if (value == null) return "";
|
||||
const token = String(value).trim();
|
||||
if (!token) return "";
|
||||
const lowered = token.toLowerCase();
|
||||
return lowered === "null" || lowered === "undefined" ? "" : token;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { requestCrudService } from "@/service/request-axios-service";
|
||||
import { authStorageGet, authStorageSet } from "@/core/auth/scoped-storage";
|
||||
import { normalizeExternalAccessToken } from "@/core/auth/external-access-token";
|
||||
|
||||
const CONSUMER_URL = import.meta.env.VITE_AIPI_CONSUMER_URL || "";
|
||||
|
||||
@@ -15,6 +16,24 @@ type UserDetailResponse = {
|
||||
};
|
||||
};
|
||||
|
||||
function readExternalUserInfo(): Record<string, unknown> {
|
||||
try {
|
||||
const raw = authStorageGet(EXTERNAL_USER_INFO_STORAGE_KEY);
|
||||
if (!raw) return {};
|
||||
const parsed = JSON.parse(raw);
|
||||
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
||||
? (parsed as Record<string, unknown>)
|
||||
: {};
|
||||
} catch {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
function readStoredYUserId(info: Record<string, unknown>): string {
|
||||
const value = info.yUserId;
|
||||
return value == null ? "" : String(value).trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* External login via yUserId + optional token (same flow as web-code Login.tsx):
|
||||
* persist tools_token, resolve user via consumer API, store userId/userInfo.
|
||||
@@ -38,10 +57,23 @@ export async function loginByYUserId(
|
||||
// 注意:接口也会返回 accessToken,但 XK/PG 及 source=accessToken 要用路由透传的
|
||||
// access_token,故登录流程随后会用 persistAccessToken 覆盖 userInfo.accessToken。
|
||||
const result = res.data ?? {};
|
||||
authStorageSet(
|
||||
EXTERNAL_USER_INFO_STORAGE_KEY,
|
||||
JSON.stringify({ ...result, yUserId }),
|
||||
);
|
||||
const previous = readExternalUserInfo();
|
||||
const next: Record<string, unknown> = { ...result, yUserId };
|
||||
const incomingAccessToken = normalizeExternalAccessToken(result.accessToken);
|
||||
if (incomingAccessToken) {
|
||||
next.accessToken = incomingAccessToken;
|
||||
} else {
|
||||
const previousAccessToken = normalizeExternalAccessToken(previous.accessToken);
|
||||
const previousYUserId = readStoredYUserId(previous);
|
||||
// Do not let an unstable upstream empty/null token wipe a usable token for
|
||||
// the same external user. Avoid carrying it across different yUserId values.
|
||||
if (previousAccessToken && previousYUserId === yUserId) {
|
||||
next.accessToken = previousAccessToken;
|
||||
} else {
|
||||
delete next.accessToken;
|
||||
}
|
||||
}
|
||||
authStorageSet(EXTERNAL_USER_INFO_STORAGE_KEY, JSON.stringify(next));
|
||||
}
|
||||
|
||||
export function persistToolsToken(token: string): void {
|
||||
@@ -56,20 +88,9 @@ export function persistToolsToken(token: string): void {
|
||||
* 用合并而非覆盖整对象,避免抹掉 loginByYUserId 从 consumer 拿到的用户信息。
|
||||
*/
|
||||
export function persistAccessToken(token: string): void {
|
||||
const trimmed = token?.trim();
|
||||
const trimmed = normalizeExternalAccessToken(token);
|
||||
if (!trimmed) return;
|
||||
let info: Record<string, unknown> = {};
|
||||
try {
|
||||
const raw = authStorageGet(EXTERNAL_USER_INFO_STORAGE_KEY);
|
||||
if (raw) {
|
||||
const parsed = JSON.parse(raw);
|
||||
if (parsed && typeof parsed === "object") {
|
||||
info = parsed as Record<string, unknown>;
|
||||
}
|
||||
}
|
||||
} catch {
|
||||
info = {};
|
||||
}
|
||||
const info = readExternalUserInfo();
|
||||
info.accessToken = trimmed;
|
||||
authStorageSet(EXTERNAL_USER_INFO_STORAGE_KEY, JSON.stringify(info));
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
/** Strategy 模块外部 iframe / 嵌入页链接(来自 Vite 环境变量) */
|
||||
|
||||
import { authStorageGet } from "@/core/auth/scoped-storage";
|
||||
import { normalizeExternalAccessToken } from "@/core/auth/external-access-token";
|
||||
|
||||
function trimTrailingSlash(url: string): string {
|
||||
return url.replace(/\/+$/, "");
|
||||
@@ -43,8 +44,7 @@ function readUserInfo(): Record<string, unknown> {
|
||||
|
||||
/** 当前登录态 accessToken(无则空串)。 */
|
||||
export function getAccessToken(): string {
|
||||
const value = readUserInfo().accessToken;
|
||||
return value == null ? "" : String(value);
|
||||
return normalizeExternalAccessToken(readUserInfo().accessToken);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-1
@@ -5,6 +5,7 @@ import {
|
||||
getKnowledgeIframeSkin,
|
||||
} from "@/core/strategy/external-links";
|
||||
import { authStorageGet } from "@/core/auth/scoped-storage";
|
||||
import { normalizeExternalAccessToken } from "@/core/auth/external-access-token";
|
||||
import { requestCrudService } from "@/service/request-axios-service";
|
||||
import ExternalIframePage from "../common/ExternalIframePage";
|
||||
|
||||
@@ -24,7 +25,7 @@ const KnowledgeBaseResourceManagement: React.FC = () => {
|
||||
|
||||
try {
|
||||
const userInfo = JSON.parse(jsonStr);
|
||||
const token = userInfo.accessToken;
|
||||
const token = normalizeExternalAccessToken(userInfo?.accessToken);
|
||||
if (!token) return;
|
||||
|
||||
const res = (await service.post(apiUrl, {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
import type { LightApp, LightAppRouteParam } from "@/strategy-components/api/light-apps";
|
||||
import { authStorageGet } from "@/core/auth/scoped-storage";
|
||||
import { normalizeExternalAccessToken } from "@/core/auth/external-access-token";
|
||||
|
||||
/** iframe 可挂载的父菜单(取自 core/page-layout/sidebar-menu.ts 的现有菜单 id)。 */
|
||||
export const MOUNT_OPTIONS: { label: string; value: string }[] = [
|
||||
@@ -142,6 +143,9 @@ export function resolveRouteParamValue(
|
||||
}
|
||||
if (param.source) {
|
||||
const value = userInfo[param.source];
|
||||
if (param.source === "accessToken") {
|
||||
return normalizeExternalAccessToken(value);
|
||||
}
|
||||
return value == null ? "" : String(value);
|
||||
}
|
||||
return "";
|
||||
|
||||
Reference in new issue
Block a user