97 lines
2.6 KiB
TypeScript
97 lines
2.6 KiB
TypeScript
/**
|
||
* 认证服务 - 前端只调用 FastAPI,不直连 PocketBase。
|
||
*/
|
||
|
||
import { PB_STORAGE_KEYS } from "./constants";
|
||
import { apiUrl } from "@/app/lib/api-client";
|
||
|
||
export interface AuthUser {
|
||
id: string;
|
||
email: string;
|
||
[key: string]: unknown;
|
||
}
|
||
|
||
export interface AuthResult {
|
||
token: string;
|
||
record: AuthUser;
|
||
is_new?: boolean;
|
||
provider?: string;
|
||
}
|
||
|
||
async function authRequest(path: string, body: Record<string, unknown>): Promise<AuthResult> {
|
||
const res = await fetch(apiUrl(path), {
|
||
method: "POST",
|
||
headers: { "Content-Type": "application/json" },
|
||
credentials: "include",
|
||
body: JSON.stringify(body),
|
||
});
|
||
if (!res.ok) {
|
||
const err = await res.json();
|
||
throw new Error(err?.detail || err?.message || "认证失败");
|
||
}
|
||
const data = await res.json();
|
||
if (!data?.token) throw new Error("登录响应异常");
|
||
return {
|
||
token: data.token,
|
||
record: data.record,
|
||
is_new: data.is_new,
|
||
provider: data.provider,
|
||
};
|
||
}
|
||
|
||
export async function emailLogin(email: string): Promise<AuthResult> {
|
||
return authRequest("/api/auth/email", { email });
|
||
}
|
||
|
||
export async function googleLogin(idToken: string): Promise<AuthResult> {
|
||
return authRequest("/api/auth/google", { id_token: idToken });
|
||
}
|
||
|
||
export function pbSaveAuth(token: string, record: AuthUser): void {
|
||
if (typeof window === "undefined") return;
|
||
localStorage.setItem(PB_STORAGE_KEYS.token, token);
|
||
localStorage.setItem(PB_STORAGE_KEYS.user, JSON.stringify(record));
|
||
}
|
||
|
||
/** 登出 - 清除本地存储、支付订单、根域 Cookie */
|
||
export async function pbLogout(): Promise<void> {
|
||
if (typeof window === "undefined") return;
|
||
localStorage.removeItem(PB_STORAGE_KEYS.token);
|
||
localStorage.removeItem(PB_STORAGE_KEYS.user);
|
||
localStorage.removeItem("join_pay_order");
|
||
try {
|
||
document.cookie = "join_pay_order=; path=/; max-age=0";
|
||
} catch {
|
||
/* ignore */
|
||
}
|
||
try {
|
||
await fetch(apiUrl("/api/auth/logout"), { method: "POST", credentials: "include" });
|
||
} catch {
|
||
/* ignore */
|
||
}
|
||
window.dispatchEvent(new CustomEvent("auth:updated"));
|
||
}
|
||
|
||
export function getStoredUser(): AuthUser | null {
|
||
if (typeof window === "undefined") return null;
|
||
try {
|
||
const raw = localStorage.getItem(PB_STORAGE_KEYS.user);
|
||
if (!raw) return null;
|
||
const user = JSON.parse(raw);
|
||
if (!user?.id || !user?.email) return null;
|
||
return user;
|
||
} catch {
|
||
return null;
|
||
}
|
||
}
|
||
|
||
export function getStoredUserEmail(): string | null {
|
||
const user = getStoredUser();
|
||
return user?.email ?? null;
|
||
}
|
||
|
||
export function getStoredToken(): string | null {
|
||
if (typeof window === "undefined") return null;
|
||
return localStorage.getItem(PB_STORAGE_KEYS.token);
|
||
}
|