身份验证响应后如何呈现反应路线?

How to render react routes after auth response?

当有人访问我的网页时,我首先检查用户是否经过身份验证。在呈现路由之前,我需要等待 GET /auth/loggedin 请求的响应,以便我知道是否应该重定向到 /login/。我已将条件呈现添加到 App.js 组件,但它总是将用户重定向到 /login,即使用户已通过身份验证。

App.js:

import { useEffect, useState } from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import AuthContext from "./contexts/authContext";
import { apiLoggedIn } from "./api/auth";
import ProtectedRoute from "./components/ProtectedRoute";
import Document from "./pages/Document";
import { Login } from "./pages/Login";
import { Signup } from "./pages/Signup";
import Layout from "./components/Layout";
import PublicRoute from "./components/PublicRoute";

export const App = () => {
  const [auth, setAuth] = useState({ isAuth: undefined, user: undefined });
  useEffect(() => {
    apiLoggedIn()
      .then((res) => {
        setAuth({ isAuth: true, user: res.data.userData });
      })
      .catch((err) => {
        if (err.response) {
          setAuth({ isAuth: false, user: {} });
        } else if (err.request) {
          setAuth({ isAuth: false, user: {} });
          console.log(err.request);
        } else {
          setAuth({ isAuth: false, user: {} });
          console.log(err.message);
        }
      });
  }, []);
  return (
    <>
      {auth.isAuth !== undefined ? (
        <AuthContext.Provider value={{ auth, setAuth }}>
          <BrowserRouter>
            <Routes>
              <Route
                path="/"
                element={
                  <ProtectedRoute redirectTo="/login">
                    <Layout />
                  </ProtectedRoute>
                }
              >
                <Route index element={<Document />} />
              </Route>
              <Route
                path="/signup"
                element={
                  <PublicRoute>
                    <Signup />
                  </PublicRoute>
                }
              />
              <Route
                path="/login"
                element={
                  <PublicRoute>
                    <Login />
                  </PublicRoute>
                }
              />
            </Routes>
          </BrowserRouter>
        </AuthContext.Provider>
      ) : (
        ""
      )}
    </>
  );
};

./api/auth.js

import axios from "axios";

export const apiLoggedIn = () => {
  return axios.get("/auth/loggedin");
};

./components/ProtectedRoute.js

import { useContext } from "react";
import AuthContext from "../contexts/authContext";
import { Navigate } from "react-router-dom";

const ProtectedRoute = ({ children, redirectTo }) => {
  const { isAuth } = useContext(AuthContext);
  return isAuth ? children : <Navigate to={redirectTo} />;
};

export default ProtectedRoute;

./components/PublicRoute.js

import { useContext } from "react";
import AuthContext from "../contexts/authContext";
import { Navigate } from "react-router-dom";

const PublicRoute = ({ children }) => {
  const { isAuth } = useContext(AuthContext);
  return isAuth ? <Navigate to={"/"} /> : children;
};

export default PublicRoute;

./contexts/authContext.js

import { createContext } from "react";

const AuthContext = createContext({
  auth: { isAuth: false, user: {} },
  setAuth: () => {},
});

export default AuthContext;

AuthContext 值是一个具有 authsetAuth 属性的对象

<AuthContext.Provider value={{ auth, setAuth }}>
  ...
</AuthContext.Provider>

但在路由包装器中,您引用了一个 isAuth 属性,它将 始终 未定义,即错误。

const ProtectedRoute = ({ children, redirectTo }) => {
  const { isAuth } = useContext(AuthContext);
  return isAuth ? children : <Navigate to={redirectTo} />;
};

这就是重定向总是发生的原因。要解决此问题,请确保在整个代码中引用相同的上下文值。

要么指定一个 isAuth 上下文值:

<AuthContext.Provider value={{ isAuth: auth.isAuth, setAuth }}>
  ...
</AuthContext.Provider>

或修复包装器:

const ProtectedRoute = ({ children, redirectTo }) => {
  const { auth } = useContext(AuthContext);
  return auth.isAuth ? children : <Navigate to={redirectTo} />;
};

...

const PublicRoute = ({ children }) => {
  const { auth } = useContext(AuthContext);
  return auth.isAuth ? <Navigate to={"/"} /> : children;
};

密钥名称未在身份验证提供程序中正确传递,应该按以下方式传递,这里是示例沙箱演示:https://codesandbox.io/s/routes-4c5oh?file=/src/App.js

<AuthContext.Provider value={{ isAuth:auth, setAuth }}>

或在每个地方将密钥更改为auth。在 Public 和受保护的路线中,例如以下

const { auth:{isAuth} } = useContext(AuthContext);

您的上下文具有以下形状:

{
  "auth": {
    "isAuth": true,
    "user": {...},
  },
  "setAuth": function ...
}

您必须将 ProtectedRoute 更新为

const ProtectedRoute = ({ children, redirectTo }) => {
  const { auth } = useContext(AuthContext);
  return auth.isAuth ? children : <Navigate to={redirectTo} />;
};

您必须将 PublicRoute 更新为

const PublicRoute = ({ children }) => {
  const { auth } = useContext(AuthContext);
  return auth.isAuth ? <Navigate to={"/"} /> : children;
};