Fix login race condition.
All checks were successful
homepanel/HomePanel/pipeline/head This commit looks good
All checks were successful
homepanel/HomePanel/pipeline/head This commit looks good
This commit is contained in:
parent
f7b4f9e8e4
commit
fc89bba581
@ -16,7 +16,7 @@ import PasswordResetHelp from "./PasswordResetHelp";
|
||||
function Login() {
|
||||
const [password, setPassword] = useState("");
|
||||
const [error, setError] = useState("");
|
||||
const { login, isLoading, isAuthenticated, passwordIsSet, siteName } =
|
||||
const { login, isLoading, isAuthenticated, passwordIsSet, siteName, lastLoggedIn } =
|
||||
useAuth();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
@ -38,6 +38,17 @@ function Login() {
|
||||
}
|
||||
}, [isAuthenticated, isLoading, navigate, from]);
|
||||
|
||||
// Navigate after successful login using lastLoggedIn timestamp
|
||||
useEffect(() => {
|
||||
if (lastLoggedIn && !isLoading) {
|
||||
// Small delay to ensure state has propagated
|
||||
const timer = setTimeout(() => {
|
||||
navigate(from, { replace: true });
|
||||
}, 50);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [lastLoggedIn, isLoading, navigate, from]);
|
||||
|
||||
const handleSubmit = async (e) => {
|
||||
e.preventDefault();
|
||||
setError("");
|
||||
@ -48,12 +59,10 @@ function Login() {
|
||||
}
|
||||
|
||||
const result = await login(password);
|
||||
if (result.success) {
|
||||
// Navigation will be handled by the useEffect when isAuthenticated becomes true
|
||||
// No need to navigate here - the useEffect will catch the state change
|
||||
} else {
|
||||
if (!result.success) {
|
||||
setError(result.error || "Invalid password");
|
||||
}
|
||||
// Navigation will be handled by the useEffect when lastLoggedIn is set
|
||||
};
|
||||
|
||||
return (
|
||||
|
||||
@ -3,7 +3,7 @@ import { Navigate, useLocation } from "react-router-dom";
|
||||
import { useAuth } from "@contexts/AuthContext";
|
||||
|
||||
function ProtectedRoute({ children }) {
|
||||
const { isAuthenticated, isLoading } = useAuth();
|
||||
const { isAuthenticated, isLoading, lastLoggedIn } = useAuth();
|
||||
const location = useLocation();
|
||||
|
||||
if (isLoading) {
|
||||
@ -11,8 +11,13 @@ function ProtectedRoute({ children }) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
// Check if user just logged in (within last 2 seconds) to handle race conditions
|
||||
const justLoggedIn = lastLoggedIn && (Date.now() - lastLoggedIn) < 2000;
|
||||
|
||||
// Check both state and sessionStorage to handle race conditions after login
|
||||
const isAuth = isAuthenticated || sessionStorage.getItem("adminAuthenticated") === "true";
|
||||
const isAuth = isAuthenticated ||
|
||||
sessionStorage.getItem("adminAuthenticated") === "true" ||
|
||||
justLoggedIn;
|
||||
|
||||
if (!isAuth) {
|
||||
// Redirect to login page with the current location as state
|
||||
|
||||
@ -32,6 +32,11 @@ export const AuthProvider = ({ children }) => {
|
||||
// Get session token from storage if available
|
||||
return sessionStorage.getItem("adminSessionToken") || null;
|
||||
});
|
||||
const [lastLoggedIn, setLastLoggedIn] = useState(() => {
|
||||
// Get last login timestamp from storage if available
|
||||
const stored = sessionStorage.getItem("adminLastLoggedIn");
|
||||
return stored ? parseInt(stored, 10) : null;
|
||||
});
|
||||
const [passwordIsSet, setPasswordIsSet] = useState(true); // Default to true to avoid redirect loop
|
||||
const [siteName, setSiteName] = useState(null);
|
||||
const [isLoading, setIsLoading] = useState(false);
|
||||
@ -58,6 +63,10 @@ export const AuthProvider = ({ children }) => {
|
||||
setSessionToken(data.data.sessionToken);
|
||||
sessionStorage.setItem("adminSessionToken", data.data.sessionToken);
|
||||
}
|
||||
// Set lastLoggedIn timestamp to handle race conditions
|
||||
const loginTime = Date.now();
|
||||
setLastLoggedIn(loginTime);
|
||||
sessionStorage.setItem("adminLastLoggedIn", loginTime.toString());
|
||||
return { success: true };
|
||||
} else {
|
||||
return {
|
||||
@ -78,8 +87,10 @@ export const AuthProvider = ({ children }) => {
|
||||
const logout = useCallback(async () => {
|
||||
setIsAuthenticated(false);
|
||||
setSessionToken(null);
|
||||
setLastLoggedIn(null);
|
||||
sessionStorage.removeItem("adminAuthenticated");
|
||||
sessionStorage.removeItem("adminSessionToken");
|
||||
sessionStorage.removeItem("adminLastLoggedIn");
|
||||
// Notify server about logout
|
||||
try {
|
||||
await fetch(`${getApiUrl()}/logout`, {
|
||||
@ -156,8 +167,10 @@ export const AuthProvider = ({ children }) => {
|
||||
} else {
|
||||
setIsAuthenticated(false);
|
||||
setSessionToken(null);
|
||||
setLastLoggedIn(null);
|
||||
sessionStorage.removeItem("adminAuthenticated");
|
||||
sessionStorage.removeItem("adminSessionToken");
|
||||
sessionStorage.removeItem("adminLastLoggedIn");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -166,8 +179,10 @@ export const AuthProvider = ({ children }) => {
|
||||
if (isAuthenticated) {
|
||||
setIsAuthenticated(false);
|
||||
setSessionToken(null);
|
||||
setLastLoggedIn(null);
|
||||
sessionStorage.removeItem("adminAuthenticated");
|
||||
sessionStorage.removeItem("adminSessionToken");
|
||||
sessionStorage.removeItem("adminLastLoggedIn");
|
||||
}
|
||||
});
|
||||
}, [isAuthenticated]); // Only run on mount or when isAuthenticated changes
|
||||
@ -175,8 +190,10 @@ export const AuthProvider = ({ children }) => {
|
||||
const setUnauthorized = useCallback(() => {
|
||||
setIsAuthenticated(false);
|
||||
setSessionToken(null);
|
||||
setLastLoggedIn(null);
|
||||
sessionStorage.removeItem("adminAuthenticated");
|
||||
sessionStorage.removeItem("adminSessionToken");
|
||||
sessionStorage.removeItem("adminLastLoggedIn");
|
||||
}, []);
|
||||
|
||||
const value = {
|
||||
@ -189,6 +206,7 @@ export const AuthProvider = ({ children }) => {
|
||||
setPassword,
|
||||
siteName,
|
||||
setUnauthorized,
|
||||
lastLoggedIn,
|
||||
};
|
||||
|
||||
return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user