feat: 添加身份一致性检查,更新登录逻辑以清除不一致的缓存
This commit is contained in:
@@ -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 (
|
||||
<div className="min-h-dvh bg-morandi-50 flex items-center justify-center p-4">
|
||||
<div className="text-center">
|
||||
<motion.div
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ repeat: Infinity, duration: 1.5, ease: "linear" }}
|
||||
className="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-br from-morandi-300 to-morandi-400 rounded-full mb-4"
|
||||
>
|
||||
<Heart className="w-8 h-8 text-white fill-white" />
|
||||
</motion.div>
|
||||
{error ? (
|
||||
<p className="text-sm text-red-500">{error}</p>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500">加载中...</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
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 (
|
||||
<div className="min-h-dvh bg-morandi-50 flex items-center justify-center p-4">
|
||||
<div className="text-center">
|
||||
<motion.div
|
||||
animate={{ rotate: 360 }}
|
||||
transition={{ repeat: Infinity, duration: 1.5, ease: "linear" }}
|
||||
className="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-br from-morandi-300 to-morandi-400 rounded-full mb-4"
|
||||
>
|
||||
<Heart className="w-8 h-8 text-white fill-white" />
|
||||
</motion.div>
|
||||
{error ? (
|
||||
<p className="text-sm text-red-500">{error}</p>
|
||||
) : (
|
||||
<p className="text-sm text-gray-500">加载中...</p>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user