diff --git a/frontend/src/app/pages/LoginPage.tsx b/frontend/src/app/pages/LoginPage.tsx
index 19528b3..6f748d4 100644
--- a/frontend/src/app/pages/LoginPage.tsx
+++ b/frontend/src/app/pages/LoginPage.tsx
@@ -1,76 +1,91 @@
-import { useEffect, useState } from "react";
-import { useNavigate } from "react-router";
-import { motion } from "motion/react";
-import { Heart } from "lucide-react";
-import { useUser } from "../context/UserContext";
-import { devLogin, fetchApi } from "../services/api";
-import { debugLog, clearDebugLogs } from "../services/debug";
-
-export function LoginPage() {
- const navigate = useNavigate();
- const { setTokenAndUser, fetchProfile } = useUser();
- const [error, setError] = useState("");
-
- useEffect(() => {
- clearDebugLogs();
-
- const params = new URLSearchParams(window.location.search);
- debugLog(`URL: ${window.location.href.substring(0, 100)}`);
- debugLog(`search: ${window.location.search}`);
-
- const openidParam = params.get('openid');
- if (openidParam && openidParam.trim()) {
- debugLog(`openid: ${openidParam}`);
- fetchApi("/auth/openid-login", {
- method: "POST",
- body: JSON.stringify({ openid: openidParam }),
- }).then((res: any) => {
- debugLog(`openid-login OK: id=${res.user_id}, phone=${res.mobile}`);
- setTokenAndUser(res.token, { id: res.user_id, openid: res.openid, phone: res.mobile });
- fetchProfile().then((dto) => {
- if (dto) debugLog(`fetchProfile: name=${dto.name}, phone=${dto.phone}, onboarded=${dto.is_onboarded}`);
- navigate(dto?.is_onboarded ? "/home" : "/onboarding", { replace: true });
- }).catch((e: any) => {
- debugLog(`fetchProfile error: ${e?.message}`);
- setError("登录已失效,请在小程序重新进入");
- });
- }).catch((e: any) => {
- debugLog(`openid-login error: ${e?.message}`);
- setError("登录失败: " + (e?.message || ""));
- });
- return;
- }
-
- debugLog(`no openid param (val=${openidParam || '(empty)'}), fallback to dev-login`);
- devLogin().then((res) => {
- debugLog(`dev-login: openid=${res.openid}, phone=${res.mobile}`);
- setTokenAndUser(res.token, { id: res.user_id, openid: res.openid, phone: res.mobile });
- fetchProfile().then((dto) => {
- if (dto) debugLog(`fetchProfile: name=${dto.name}, phone=${dto.phone}`);
- navigate(dto?.is_onboarded ? "/home" : "/onboarding", { replace: true });
- });
- }).catch((err) => {
- debugLog(`dev-login error: ${err?.message}`);
- setError(err?.message || "登录失败,请刷新重试");
- });
- }, []); // eslint-disable-line react-hooks/exhaustive-deps
-
- return (
-
-
-
-
-
- {error ? (
-
{error}
- ) : (
-
加载中...
- )}
-
-
- );
-}
+import { useEffect, useState } from "react";
+import { useNavigate } from "react-router";
+import { motion } from "motion/react";
+import { Heart } from "lucide-react";
+import { useUser } from "../context/UserContext";
+import { devLogin, fetchApi, getToken, clearToken, decodeToken } from "../services/api";
+import { debugLog, clearDebugLogs } from "../services/debug";
+
+export function LoginPage() {
+ const navigate = useNavigate();
+ const { setTokenAndUser, fetchProfile } = useUser();
+ const [error, setError] = useState("");
+
+ useEffect(() => {
+ clearDebugLogs();
+
+ // 身份一致性检查:URL 中的 openid 与缓存 token 不一致时清除缓存
+ const urlOpenid = new URLSearchParams(window.location.search).get('openid');
+ const cachedToken = getToken();
+ if (urlOpenid && cachedToken) {
+ try {
+ const payload = decodeToken(cachedToken);
+ if (payload.openid !== urlOpenid) {
+ debugLog(`[auth] openid 不一致: URL=${urlOpenid}, cache=${payload.openid},清除缓存`);
+ clearToken();
+ }
+ } catch (e) {
+ debugLog(`[auth] token 解码失败: ${e}`);
+ }
+ }
+
+ const params = new URLSearchParams(window.location.search);
+ debugLog(`URL: ${window.location.href.substring(0, 100)}`);
+ debugLog(`search: ${window.location.search}`);
+
+ const openidParam = params.get('openid');
+ if (openidParam && openidParam.trim()) {
+ debugLog(`openid: ${openidParam}`);
+ fetchApi("/auth/openid-login", {
+ method: "POST",
+ body: JSON.stringify({ openid: openidParam }),
+ }).then((res: any) => {
+ debugLog(`openid-login OK: id=${res.user_id}, phone=${res.mobile}`);
+ setTokenAndUser(res.token, { id: res.user_id, openid: res.openid, phone: res.mobile });
+ fetchProfile().then((dto) => {
+ if (dto) debugLog(`fetchProfile: name=${dto.name}, phone=${dto.phone}, onboarded=${dto.is_onboarded}`);
+ navigate(dto?.is_onboarded ? "/home" : "/onboarding", { replace: true });
+ }).catch((e: any) => {
+ debugLog(`fetchProfile error: ${e?.message}`);
+ setError("登录已失效,请在小程序重新进入");
+ });
+ }).catch((e: any) => {
+ debugLog(`openid-login error: ${e?.message}`);
+ setError("登录失败: " + (e?.message || ""));
+ });
+ return;
+ }
+
+ debugLog(`no openid param (val=${openidParam || '(empty)'}), fallback to dev-login`);
+ devLogin().then((res) => {
+ debugLog(`dev-login: openid=${res.openid}, phone=${res.mobile}`);
+ setTokenAndUser(res.token, { id: res.user_id, openid: res.openid, phone: res.mobile });
+ fetchProfile().then((dto) => {
+ if (dto) debugLog(`fetchProfile: name=${dto.name}, phone=${dto.phone}`);
+ navigate(dto?.is_onboarded ? "/home" : "/onboarding", { replace: true });
+ });
+ }).catch((err) => {
+ debugLog(`dev-login error: ${err?.message}`);
+ setError(err?.message || "登录失败,请刷新重试");
+ });
+ }, []); // eslint-disable-line react-hooks/exhaustive-deps
+
+ return (
+
+
+
+
+
+ {error ? (
+
{error}
+ ) : (
+
加载中...
+ )}
+
+
+ );
+}