react路由器dom v6总是重定向到登录路由,即使用户已通过身份验证



我试图为订单路由器实现受保护的路由,但即使用户经过身份验证,它也总是重定向到登录。我使用了react router dom中的Navigate组件,并将app.js的isAuth状态传递给了privateRoute.js组件,我在privateRoute.js中收到了isAuth作为道具,但如果我不使用导航组件,那么当用户进行身份验证时,我会得到isAuth true,但我使用了导航组件,然后它在isAuth设置为true之前重定向到登录路由。需要帮助!!

//app.js
function App(props) {
const navigate = useNavigate();
const [authState, setAuthState] = useState({
isAuth: false,
token: null,
userId: null,
});
const [showNav, setShowNav] = useState(true);
useEffect(() => {
if (window.location.href.includes("admin")) {
setShowNav(false);
}
const token = localStorage.getItem("token");
const expiryDate = localStorage.getItem("expiryDate");
if (!token || !expiryDate) {
return;
}
const userId = localStorage.getItem("userId");
const remainingMilliseconds =
new Date(expiryDate).getTime() - new Date().getTime();
setAuthState((prevState) => {
return {
...prevState,
isAuth: true,
token: token,
userId: userId,
};
});
setAutoLogout(remainingMilliseconds);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [authState.isAuth]);

const handleUserCredentialsSubmission = (userData, setErrors) => {
const formData = new FormData();
formData.append("name", userData.name);
formData.append("email", userData.email);
formData.append("password", userData.password);

fetch("http://localhost:3080/signup", { method: "POST", body: formData })
.then((res) => {
if (res.status !== 200 && res.status !== 201) {
if (res.status === 409) {
throw new Error("Email address already exists!");
} else {
throw new Error("Creating a user failed!");
}
}
return res.json();
})
.then((resData) => {
navigate("/login");
})
.catch((err) => {
setErrors((prevState) => {
return {
...prevState,
signupError: err.message,
};
});
throw new Error(err);
});
};

const logoutHandler = () => {
setAuthState((prevState) => {
return {
...prevState,
isAuth: false,
token: null,
};
});
localStorage.removeItem("token");
localStorage.removeItem("userId");
localStorage.removeItem("expiryDate");
navigate("/login");
};

const setAutoLogout = (remainingTime) => {
setTimeout(() => {
logoutHandler();
}, remainingTime);
};

const handleUserlogin = (userData, setErrors, setUserCredentials) => {
const formData = new FormData();
formData.append("email", userData.email);
formData.append("password", userData.password);

fetch("http://localhost:3080/login", { method: "POST", body: formData })
.then((res) => {
if (res.status !== 200 && res.status !== 201) {
throw new Error("Invalid Email Address & Password");
}
return res.json();
})
.then((resData) => {
setAuthState((prevState) => {
return {
...prevState,
isAuth: true,
token: resData.token,
userId: resData.userId,
};
});
localStorage.setItem("token", resData.token);
localStorage.setItem("userId", resData.userId);
const remainingMilliseconds = 60 * 60 * 1000;
const expiryDate = new Date(
new Date().getTime() + remainingMilliseconds
);
localStorage.setItem("expiryDate", expiryDate.toISOString());
navigate("/");
})
.catch((err) => {
setAuthState((prevState) => {
return {
...prevState,
isAuth: false,
token: null,
userId: null,
};
});
setUserCredentials((prevState) => {
return {
...prevState,
email: "",
password: "",
};
});
setErrors((prevState) => {
return {
...prevState,
loginError: err.message,
};
});
throw new Error(err);
});
};

const handleAddToCart = (productId) => {
fetch("http://localhost:3080/cart", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + authState.token,
},
body: JSON.stringify({
prodId: productId,
}),
})
.then((res) => {
if (res.status !== 200 && res.status !== 201) {
throw new Error("User does not Exists");
}
return res.json();
})
.then((resData) => {
navigate("/cart");
})
.catch((err) => {
throw new Error(err);
});
};
console.log(authState.isAuth);

return (
<div className="App">
{showNav && (
<Nav
token={authState.token}
isAuth={authState.isAuth}
onLogout={logoutHandler}
/>
)}
{/* <Nav /> */}
<Routes>
<Route
path="/product"
element={
<Product isAuth={authState.isAuth} AddToCart={handleAddToCart} />
}
/>
<Route
path="/product/:productId"
element={
<ProductDetails
{...props}
isAuth={authState.isAuth}
AddToCart={handleAddToCart}
/>
}
/>
<Route path="/cart" element={<Cart token={authState.token} />} />
<Route
path="/orders"
element={
<PrivateRoute {...authState}>
<Orders token={authState.token} />
</PrivateRoute>
}
/>
<Route
path="/checkout"
element={<Checkout token={authState.token} />}
/>
<Route path="/login" element={<Login onSingIn={handleUserlogin} />} />
<Route
path="/signup"
element={<Signup onSignUp={handleUserCredentialsSubmission} />}
/>
<Route path="/admin/*" element={<Admin />}>
<Route
path="product"
element={<AddProduct token={authState.token} />}
/>
<Route path="products" element={<AdminProducts Admin={!showNav} />} />
</Route>
<Route path="/" element={<Home />} />
{/* <Route path="*" element={<Navigate to="/" />} /> */}
</Routes>
</div>
);
}

export default App;
//privateRoute.js
const PrivateRoute = (props) => {
console.log(props.isAuth);
if (!props.isAuth) {
return <Navigate to="/login" replace />;
}
return props.children;
};
export default PrivateRoute;

authState.isAuth状态的初始值看起来与;未经认证的";状态,因此当应用程序最初正在加载/装载,并且用户处于受保护的路由上时,PrivateRoute会将其弹到登录路由以进行身份验证。

使用不是已确认/已验证/已验证身份验证状态值之一的初始authState.isAuth值。换句话说,除了truefalse之外的任何。更新PrivateRoute组件以检查此初始条件,并有条件地呈现null或某些加载指示符,直到确认身份验证状态。

应用

const [authState, setAuthState] = useState({
isAuth: undefined,
token: null,
userId: null,
});

privateRoute.js

const PrivateRoute = ({ isAuth }) => {
if (isAuth === undefined) {
return null; // or loading indicator/spinner/etc
}
return isAuth
? children
: <Navigate to="/login" replace />;
};

请注意,您需要为未经身份验证的逻辑路径显式设置authState.isAuth状态,即身份验证失败、令牌过期等。

最新更新