首页 > 解决方案 > React Protected Routes API 调用

问题描述

我有一个 React 受保护的路由组件,它包裹着我的路由以启用对它们的身份验证。受保护的路由调用 API 端点来检查存储在 HTTP Only cookie 中的 JWT 是否有效。如果是,则呈现与请求的路由关联的组件,如果不是,则返回登录页面。

import React, { useState, useContext } from 'react';
import { Route, Redirect } from 'react-router-dom';
import axios from 'axios';
import { UserContext } from '../functions/UserContext';

const ProtectedRoute = ({ component: Component, ...rest }) => {
  const [isAuthenticated, setIsAuthenticated] = useState(0);
  const [gotResponse, setGotResponse] = useState(0);
  const { user, setUser } = useContext(UserContext);

  axios
    .post(
      process.env.REACT_APP_API_URL + '/api/auth/checkauth/',
      { content: 'checkAuthStatus' },
      {
        headers: { 'Content-Type': 'application/json' },
        withCredentials: true,
      }
    )
    .then((res) => {
      setUser(res.data.firstName + ' ' + res.data.lastName);
      setIsAuthenticated(1);
      setGotResponse(1);
    })
    .catch(function (error) {
      setIsAuthenticated(0);
      setGotResponse(1);
    });

  if (gotResponse === 1) {
    return (
      <Route
        {...rest}
        render={(props) => {
          if (isAuthenticated === 1) {
            return <Component {...rest} {...props} />;
          } else {
            return (
              <Redirect
                to={{
                  pathname: '/login',
                  state: {
                    from: props.location,
                  },
                }}
              />
            );
          }
        }}
      />
    );
  } else {
    return null;
  }
};

export default ProtectedRoute;

我的大部分路由发生的主要 app.js 文件如下所示;

function App() {
  const [user, setUser] = useState();

  return (
    <main>
      <Switch>
        <UserContext.Provider value={{ user, setUser }}>
          <Route
            exact
            path="/login"
            render={(props) => <Login {...props} />}
          ></Route>
          <ProtectedRoute
            exact
            path="/account"
            component={Account}
            title="Account"
          ></ProtectedRoute>
          <ProtectedRoute
            exact
            path="/staff"
            component={Staff}
          ></ProtectedRoute>
          <ProtectedRoute
            exact
            path="/security"
            component={Security}
          ></ProtectedRoute>
          <ProtectedRoute exact path="/" component={Home}></ProtectedRoute>

          <Route exact path="/2fa" component={Tfa}></Route>
        </UserContext.Provider>
        <Route component={NotFound}></Route>
      </Switch>
    </main>
  );
}

export default App;

当应用程序正在运行并且我加载登录页面或任何其他受保护的路由时,我看到对 checkauth API 端点的许多相同请求。 Chrome 网络选项卡屏幕截图

这是因为 React 将我的所有路由加载到一个块中,因此在每个页面加载时为每个路由调用 checkauth 端点?我有点难过。

TIA

标签: javascriptreactjsreact-router

解决方案


感谢sojin的提示。我将 api 调用逻辑移动到我的主应用程序函数中,如下所示;

function App() {
  const [user, setUser] = useState();
  const [authentication, setAuthentication] = useState({
    authenticated: false,
    initializing: true,
  });

  useEffect(() => {
    axios
      .post(
        process.env.REACT_APP_API_URL + '/api/auth/checkauth/',
        { content: 'checkAuthStatus' },
        {
          headers: { 'Content-Type': 'application/json' },
          withCredentials: true,
        }
      )
      .then((res) => {
        setUser(res.data.firstName + ' ' + res.data.lastName);
        setAuthentication({
          authenticated: true,
          initializing: false,
        });
      })
      .catch(function (error) {
        setAuthentication({
          authenticated: false,
          initializing: false,
        });
      });
  }, [setAuthentication]);

  if (authentication.initializing) {
    return <div>Loading</div>;
  }
  return (
    <main>
      <React.StrictMode>
        <Switch>
          <UserContext.Provider value={{ user, setUser }}>
            <Route
              exact
              path="/login"
              render={(props) => <Login {...props} />}
            ></Route>
            <ProtectedRoute
              exact
              path="/account"
              component={Account}
              title="Account"
              authenticated={authentication.authenticated}
            ></ProtectedRoute>
            <Route exact path="/staff" component={Staff}></Route>
            <ProtectedRoute
              exact
              path="/security"
              component={Security}
              authenticated={authentication.authenticated}
            ></ProtectedRoute>
            <ProtectedRoute
              exact
              path="/"
              component={Home}
              authenticated={authentication.authenticated}
            ></ProtectedRoute>

            <Route exact path="/2fa" component={Tfa}></Route>
          </UserContext.Provider>
          <Route component={NotFound}></Route>
        </Switch>
      </React.StrictMode>
    </main>
  );
}

export default App;

并像这样调整受保护的路线;

const ProtectedRoute = ({ component: Component, authenticated, ...rest }) => {
  return (
    <Route
      {...rest}
      render={(props) => {
        if (authenticated) {
          return <Component {...rest} {...props} />;
        } else {
          return (
            <Redirect
              to={{
                pathname: '/login',
                state: {
                  from: props.location,
                },
              }}
            />
          );
        }
      }}
    />
  );
};

export default ProtectedRoute;

我现在只看到在每个页面加载时都按预期命中了 checkauth 端点的单个实例。非常感谢!


推荐阅读