【问题标题】:React-router: ProtectedRoute authentication logic not workingReact-router:ProtectedRoute 身份验证逻辑不起作用
【发布时间】:2021-05-26 18:35:51
【问题描述】:

我正在尝试实现仅在用户登录后才能访问的受保护路由。

基本上有两条路线:/loginLogin 组件(公共)和/Dashboard 组件(受保护)。用户点击/login中的Login按钮后,会调用一个API,返回一个accessToken,然后存储在localStorage中。 protectedRoute HOC 检查令牌是否存在于 localStorage 中并相应地重定向用户。

点击Login 按钮后,它只是重定向回登录页面,而不是把用户带到Dashboard。不知道逻辑有什么问题。

asyncLocalStorage 只是基于 Promise 的 localStorage 操作的辅助方法。

App.js

import { useEffect, useState } from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";
import Dashboard from "./Dashboard";
import Login from "./Login";
import ProtectedRoute from "./ProtectedRoute";
import { asyncLocalStorage } from "./asyncLocalStorage";

function App() {
  const [auth, setAuth] = useState(false);

  useEffect(() => {
    const getToken = async () => {
      const token = await asyncLocalStorage.getItem("accessToken");
      if (token) setAuth(true);
    };
    getToken();
  }, []);

  return (
    <div className="app">
      <Router>
        <Switch>
          <ProtectedRoute exact path="/" isLoggedIn={auth} redirectTo="/login">
            <Dashboard />
          </ProtectedRoute>

          <Route exact path="/login">
            <Login />
          </Route>
        </Switch>
      </Router>
    </div>
  );
}

export default App;

ProtectedRoute.js

import { Route, Redirect } from "react-router-dom";

const ProtectedRoute = ({ children, isLoggedIn, redirectTo, ...rest }) => {
  return (
    <Route
      {...rest}
      render={() => {
        return isLoggedIn ? children : <Redirect to={redirectTo} />;
      }}
    />
  );
};

export default ProtectedRoute;

仪表板.js

const Dashboard = () => {
  return (
    <div>
      <h3>Dashboard</h3>
      <button
        onClick={() => {
          localStorage.removeItem("accessToken");
          window.location.href = "/login";
        }}
      >
        Logout
      </button>
    </div>
  );
};

export default Dashboard;

登录.js

import { asyncLocalStorage } from "./asyncLocalStorage";

const Login = () => {
  return (
    <div>
      <h3>Login</h3>
      <button
        onClick={async () => {
          // Making an API call here and storing the accessToken in localStorage.
          await asyncLocalStorage.setItem(
            "accessToken",
            "SOME_TOKEN_FROM_API_RES"
          );
          window.location.href = "/";
        }}
      >
        Login
      </button>
    </div>
  );
};

export default Login;

asyncLocalStorage.js

export const asyncLocalStorage = {
  setItem: (key, value) => {
    Promise.resolve(localStorage.setItem(key, value));
  },
  getItem: (key) => {
    return Promise.resolve(localStorage.getItem(key));
  }
};

【问题讨论】:

  • 异步操作的顺序经常是个问题。我看到您正在使用await,但您可能仍然在设置auth 之前点击重定向。这有帮助吗?:stackoverflow.com/a/66358676/10431574
  • 找到了!就是你只在挂载时运行设置auth 一次的效果,所以ProtectedRoute 总是 得到isLoggedIn={false}

标签: javascript reactjs authentication react-router react-router-dom


【解决方案1】:

问题:auth 状态从未更新

您的ProtectedRoute 组件依赖于AppuseState 中的auth 的值,以确定用户是否已登录。您可以通过useEffect 挂钩设置此值,该挂钩在安装App 时运行一次。这个钩子永远不会再次运行,setAuth 永远不会在其他任何地方调用。如果用户在首次挂载App 时已注销,那么ProtectedRoute始终接收isLoggedIn={false},即使在用户已登录并且已设置本地存储之后也是如此。

解决方案:从Login 调用setAuth

典型的设置会从 ProtectedRoute 检查 localStorage,但我认为这不适用于您在此处的 async 设置。

我建议您将isLoggedInsetAuth 都传递给Login 组件。

<Login isLoggedIn={!!auth} setAuth={setAuth}/>

Login 组件中,每当我们获得trueisLoggedIn 时,我们都会重定向到主页。如果用户在已经登录时尝试转到"/login",他们将被重定向回来。当通过单击按钮登录时,当auth 的值更改为true 时,它们将被重定向。所以我们需要改变这个值。

buttononClick 处理程序将 await 设置存储中的令牌,然后调用 setAuth(token)。这将触发重定向。

import { asyncLocalStorage } from "./asyncLocalStorage";
import {Redirect} from "react-router-dom";
const Login = ({isLoggedIn, setAuth}) => {
  if ( isLoggedIn ) {
    return <Redirect to="/"/>
  }
  return (
    <div>
      <h3>Login</h3>
      <button
        onClick={async () => {
          // Making an API call here and storing the accessToken in localStorage.
          const token = "SOME_TOKEN_FROM_API_RES";
          await asyncLocalStorage.setItem(
            "accessToken",
            token
          );
          setAuth(token);
        }}
      >
        Login
      </button>
    </div>
  );
};

export default Login;

【讨论】:

  • 检查“ProtectedRoute.js 中的 localStorage”方法实际上对我有用,但是这种方法似乎更好,因为 localStorage 操作少了一个。谢谢!!
猜你喜欢
  • 2012-06-11
  • 1970-01-01
  • 2012-10-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-11-11
相关资源
最近更新 更多