You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
84 lines
2.5 KiB
84 lines
2.5 KiB
import { storageGet, storageSet, storageRemove } from './storage';
|
|
|
|
/* ===================== 双 Token 存储(access + refresh) =====================
|
|
* 规范 §4:Access Token 用于业务请求;Refresh Token 只提交给 /auth/refresh。
|
|
*
|
|
* 鉴权请求头在 fetch 构造时是「同步」的,但 AsyncStorage 是异步的,
|
|
* 因此这里保留一份内存单例,供请求层同步读取 accessToken;
|
|
* 持久化仍走 storage(qingsongpin: 前缀),由 hydrateTokens 在启动时回填。
|
|
*/
|
|
|
|
const KEY_ACCESS = 'auth:accessToken';
|
|
const KEY_REFRESH = 'auth:refreshToken';
|
|
const KEY_EXP = 'auth:expiresAt';
|
|
|
|
export interface TokenPair {
|
|
accessToken: string;
|
|
refreshToken: string;
|
|
/** accessToken 过期时间戳(毫秒);后端可能不返回,故可选 */
|
|
expiresAt?: number;
|
|
}
|
|
|
|
let memory: TokenPair | null = null;
|
|
|
|
/** 应用启动时调用一次:从持久化回填内存态;失败静默降级为未登录 */
|
|
export async function hydrateTokens(): Promise<void> {
|
|
try {
|
|
const [access, refresh, exp] = await Promise.all([
|
|
storageGet(KEY_ACCESS),
|
|
storageGet(KEY_REFRESH),
|
|
storageGet(KEY_EXP),
|
|
]);
|
|
if (access && refresh) {
|
|
memory = {
|
|
accessToken: access,
|
|
refreshToken: refresh,
|
|
expiresAt: exp ? Number(exp) : undefined,
|
|
};
|
|
}
|
|
} catch {
|
|
/* 降级为未登录 */
|
|
}
|
|
}
|
|
|
|
/** 同步读取 accessToken(供请求层构造 Authorization 头) */
|
|
export function getAccessToken(): string | null {
|
|
return memory?.accessToken ?? null;
|
|
}
|
|
|
|
/** 同步读取完整 Token 对(供刷新判断是否有 refreshToken) */
|
|
export function getTokens(): TokenPair | null {
|
|
return memory;
|
|
}
|
|
|
|
/** 写入并持久化;expiresAt 缺省时不覆盖已存值 */
|
|
export async function setTokens(
|
|
accessToken: string,
|
|
refreshToken: string,
|
|
expiresAt?: number,
|
|
): Promise<void> {
|
|
memory = { accessToken, refreshToken, expiresAt };
|
|
const writes: Promise<void>[] = [
|
|
storageSet(KEY_ACCESS, accessToken),
|
|
storageSet(KEY_REFRESH, refreshToken),
|
|
];
|
|
if (expiresAt !== undefined) {
|
|
writes.push(storageSet(KEY_EXP, String(expiresAt)));
|
|
}
|
|
await Promise.all(writes);
|
|
}
|
|
|
|
/** 清空(登出 / 刷新失败 / 401 清会话):内存与持久化一并清 */
|
|
export async function clearTokens(): Promise<void> {
|
|
memory = null;
|
|
await Promise.all([
|
|
storageRemove(KEY_ACCESS),
|
|
storageRemove(KEY_REFRESH),
|
|
storageRemove(KEY_EXP),
|
|
]);
|
|
}
|
|
|
|
/** 仅供测试:复位内存态,避免用例间污染 */
|
|
export function __resetTokenMemory(): void {
|
|
memory = null;
|
|
}
|
|
|