fix: cache yuser login info by user id
This commit is contained in:
1 parent
a046d19ce1
commit
006c5bc4c1
1 file changed
+87
-15
@@ -9,6 +9,8 @@ export const EXTERNAL_USER_ID_STORAGE_KEY = "userId";
|
|||||||
export const EXTERNAL_USER_INFO_STORAGE_KEY = "userInfo";
|
export const EXTERNAL_USER_INFO_STORAGE_KEY = "userInfo";
|
||||||
export const GENERAL_QA_ROUTE = "/page/workspace/chats/new";
|
export const GENERAL_QA_ROUTE = "/page/workspace/chats/new";
|
||||||
|
|
||||||
|
const YUSER_INFO_CACHE_KEY = "deerflow.yuserInfoByYUserId";
|
||||||
|
|
||||||
type UserDetailResponse = {
|
type UserDetailResponse = {
|
||||||
data?: {
|
data?: {
|
||||||
id?: string;
|
id?: string;
|
||||||
@@ -34,6 +36,84 @@ function readStoredYUserId(info: Record<string, unknown>): string {
|
|||||||
return value == null ? "" : String(value).trim();
|
return value == null ? "" : String(value).trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function isPlainObject(value: unknown): value is Record<string, unknown> {
|
||||||
|
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
function isUsableExternalValue(value: unknown): boolean {
|
||||||
|
if (value == null) return false;
|
||||||
|
if (typeof value !== "string") return true;
|
||||||
|
const trimmed = value.trim();
|
||||||
|
if (!trimmed) return false;
|
||||||
|
const lowered = trimmed.toLowerCase();
|
||||||
|
return lowered !== "null" && lowered !== "undefined";
|
||||||
|
}
|
||||||
|
|
||||||
|
function readYUserInfoCache(): Record<string, Record<string, unknown>> {
|
||||||
|
if (typeof window === "undefined") return {};
|
||||||
|
try {
|
||||||
|
const raw = window.localStorage.getItem(YUSER_INFO_CACHE_KEY);
|
||||||
|
if (!raw) return {};
|
||||||
|
const parsed = JSON.parse(raw);
|
||||||
|
if (!isPlainObject(parsed)) return {};
|
||||||
|
const cache: Record<string, Record<string, unknown>> = {};
|
||||||
|
for (const [key, value] of Object.entries(parsed)) {
|
||||||
|
if (isPlainObject(value)) cache[key] = value;
|
||||||
|
}
|
||||||
|
return cache;
|
||||||
|
} catch {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function readCachedYUserInfo(yUserId: string): Record<string, unknown> {
|
||||||
|
return readYUserInfoCache()[yUserId] ?? {};
|
||||||
|
}
|
||||||
|
|
||||||
|
function writeCachedYUserInfo(yUserId: string, info: Record<string, unknown>): void {
|
||||||
|
if (typeof window === "undefined") return;
|
||||||
|
try {
|
||||||
|
const cache = readYUserInfoCache();
|
||||||
|
cache[yUserId] = info;
|
||||||
|
window.localStorage.setItem(YUSER_INFO_CACHE_KEY, JSON.stringify(cache));
|
||||||
|
} catch {
|
||||||
|
/* noop */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function buildExternalUserInfo(
|
||||||
|
yUserId: string,
|
||||||
|
result: Record<string, unknown>,
|
||||||
|
previous: Record<string, unknown>,
|
||||||
|
cached: Record<string, unknown>,
|
||||||
|
): Record<string, unknown> {
|
||||||
|
const next: Record<string, unknown> = { ...cached };
|
||||||
|
for (const [key, value] of Object.entries(result)) {
|
||||||
|
if (isUsableExternalValue(value)) {
|
||||||
|
next[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next.yUserId = yUserId;
|
||||||
|
|
||||||
|
const incomingAccessToken = normalizeExternalAccessToken(result.accessToken);
|
||||||
|
if (incomingAccessToken) {
|
||||||
|
next.accessToken = incomingAccessToken;
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
const previousYUserId = readStoredYUserId(previous);
|
||||||
|
const previousAccessToken =
|
||||||
|
previousYUserId === yUserId ? normalizeExternalAccessToken(previous.accessToken) : "";
|
||||||
|
const cachedAccessToken = normalizeExternalAccessToken(cached.accessToken);
|
||||||
|
const fallbackAccessToken = previousAccessToken || cachedAccessToken;
|
||||||
|
if (fallbackAccessToken) {
|
||||||
|
next.accessToken = fallbackAccessToken;
|
||||||
|
} else {
|
||||||
|
delete next.accessToken;
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* External login via yUserId + optional token (same flow as web-code Login.tsx):
|
* External login via yUserId + optional token (same flow as web-code Login.tsx):
|
||||||
* persist tools_token, resolve user via consumer API, store userId/userInfo.
|
* persist tools_token, resolve user via consumer API, store userId/userInfo.
|
||||||
@@ -58,22 +138,10 @@ export async function loginByYUserId(
|
|||||||
// access_token,故登录流程随后会用 persistAccessToken 覆盖 userInfo.accessToken。
|
// access_token,故登录流程随后会用 persistAccessToken 覆盖 userInfo.accessToken。
|
||||||
const result = res.data ?? {};
|
const result = res.data ?? {};
|
||||||
const previous = readExternalUserInfo();
|
const previous = readExternalUserInfo();
|
||||||
const next: Record<string, unknown> = { ...result, yUserId };
|
const cached = readCachedYUserInfo(yUserId);
|
||||||
const incomingAccessToken = normalizeExternalAccessToken(result.accessToken);
|
const next = buildExternalUserInfo(yUserId, result, previous, cached);
|
||||||
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));
|
authStorageSet(EXTERNAL_USER_INFO_STORAGE_KEY, JSON.stringify(next));
|
||||||
|
writeCachedYUserInfo(yUserId, next);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function persistToolsToken(token: string): void {
|
export function persistToolsToken(token: string): void {
|
||||||
@@ -93,4 +161,8 @@ export function persistAccessToken(token: string): void {
|
|||||||
const info = readExternalUserInfo();
|
const info = readExternalUserInfo();
|
||||||
info.accessToken = trimmed;
|
info.accessToken = trimmed;
|
||||||
authStorageSet(EXTERNAL_USER_INFO_STORAGE_KEY, JSON.stringify(info));
|
authStorageSet(EXTERNAL_USER_INFO_STORAGE_KEY, JSON.stringify(info));
|
||||||
|
const yUserId = readStoredYUserId(info);
|
||||||
|
if (yUserId) {
|
||||||
|
writeCachedYUserInfo(yUserId, info);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in new issue
Block a user