使用 UseEffect 保护路由

问题描述 投票:0回答:1

我遇到了状态问题,当通过 PrivateRoute.jsx 传递时,我的状态没有更新

这是我的App.jsx

  const [isUserLogged, setIsUserLogged] = useState(false);

  useEffect(() => {
    const getUserID = async () => {
      try {
        await Axios.get("http://localhost:3001/verifylogin").then((res) => {
          if (res.data !== "User not found") {
            setIsUserLogged(true);
          } else {
            setIsUserLogged(false);
          }
        });
      } catch (error) {}
    };
    getUserID();
  }, []);

  const router = createBrowserRouter(
    createRoutesFromElements(
      <Route path="/" element={<RootLayouts />}>
        <Route index element={<LandingPage />} />
         <CODE BELOW>
      </Route>
    )
  );

  return <RouterProvider router={router} />;

代码如下:

我尝试了三件事:

App.jsx 中第一

      <Route
          path="/admindashboard"
          element={!isUserLogged ? <Navigate to="/" /> : <Dashboard />}
        />

PrivateRoutes.jsx 中第二

const PrivateRoute = ({ children, privateRole }) => {
  const [isAuthorized, setIsAuthorized] = useState(false);
  Axios.defaults.withCredentials = true;
  useEffect(() => {
    Axios.get("http://localhost:3001/verifylogin").then((res) => {
      if (res.data !== "User not found") {
        console.log(res.data.role);
        setIsAuthorized(res.data.role === privateRole);
      } else {
        setIsAuthorized(false);
      }
    });
  }, []);

  return isAuthorized ? children : <Navigate to="/" />;
};

export default PrivateRoute;

PrivateRoutes.jsx 中的

第三个

const PrivateRoute = ({ children, privateRole, userRole, isUserLogged }) => {
  console.log(privateRole, userRole, isUserLogged);

  Axios.defaults.withCredentials = true;
  useEffect(() => {
    Axios.get("http://localhost:3001/verifylogin").then((res) => {
      if (res.data !== "User not found") {
        setUserDetails(res.data);
      } else {
        navigate("/");
      }
    });
  }, []);
  
  if (isUserLogged && privateRole === userRole) {
    return children;
  } else {
    return <Navigate to="/" replace />;
  }
};

export default PrivateRoute;

/verifylogin 的作用基本上是获取可用的令牌 cookie 并解码 JWT 令牌并检索用户的所有数据(id、角色、名称)。我遇到的问题是它没有通过最新状态,因为我正在使用 useEffect。它只读取第一个/初始状态,因此它始终为 false 或 null。我该如何解决这个问题?

reactjs node.js react-router
1个回答
0
投票

您面临的问题主要是由于您如何尝试使用 React Router v6 在 React 应用程序中管理身份验证和基于角色的访问控制。状态更新和 HTTP 请求的异步性质与 React 中的初始渲染行为相结合,可能会导致组件决定渲染内容时状态尚未更新的情况。

以下是一些改进和解决

PrivateRoute
组件和整体身份验证流程问题的策略:

  1. 集中状态和身份验证逻辑 不要检查每个
    PrivateRoute
    中的身份验证状态,而是考虑使用全局上下文 (
    AuthContext
    ) 来管理用户身份验证和角色。这样,您的身份验证逻辑就位于一个位置,您可以轻松访问整个应用程序中的用户状态。

首先,创建身份验证上下文:

// AuthContext.js
import React, { createContext, useContext, useState, useEffect } from 'react';
import Axios from 'axios';

const AuthContext = createContext();

export const AuthProvider = ({ children }) => {
  const [isUserLogged, setIsUserLogged] = useState(false);
  const [userRole, setUserRole] = useState(null);

  useEffect(() => {
    Axios.defaults.withCredentials = true;
    const verifyLogin = async () => {
      try {
        const res = await Axios.get("http://localhost:3001/verifylogin");
        if (res.data !== "User not found") {
          setIsUserLogged(true);
          setUserRole(res.data.role);
        } else {
          setIsUserLogged(false);
          setUserRole(null);
        }
      } catch (error) {
        console.error('Authentication error:', error);
      }
    };

    verifyLogin();
  }, []);

  return (
    <AuthContext.Provider value={{ isUserLogged, userRole }}>
      {children}
    </AuthContext.Provider>
  );
};

// Custom hook to use auth context
export const useAuth = () => useContext(AuthContext);
  1. 修改
    App.jsx
    以使用
    AuthProvider
    AuthProvider
    :
  2. 包裹应用程序的组件树
// In App.jsx
import { AuthProvider } from './AuthContext';

const App = () => {
  return (
    <AuthProvider>
      <RouterProvider router={router} />
    </AuthProvider>
  );
};
  1. 更新
    PrivateRoute
    以使用
    AuthContext
    修改你的
    PrivateRoute
    以直接消耗
    AuthContext
    。这样,它就会自动对身份验证状态的变化做出反应:
// PrivateRoute.jsx
import React from 'react';
import { Navigate } from 'react-router-dom';
import { useAuth } from './AuthContext';

const PrivateRoute = ({ children, privateRole }) => {
  const { isUserLogged, userRole } = useAuth();

  if (!isUserLogged) {
    // User not logged in
    return <Navigate to="/" replace />;
  } else if (privateRole && privateRole !== userRole) {
    // User doesn't have the right role
    return <Navigate to="/unauthorized" replace />;
  }

  return children; // User is logged in and has the right role (if specified)
};

export default PrivateRoute;
  1. 使用
    PrivateRoute
    您现在可以在路由配置中使用
    PrivateRoute
    ,知道它将正确响应身份验证状态和用户角色的更改:
// Inside your router configuration
<Route path="/admindashboard" element={
  <PrivateRoute privateRole="admin">
    <Dashboard />
  </PrivateRoute>
}/>
© www.soinside.com 2019 - 2024. All rights reserved.