React Router中的用户身份验证

时间:2020-03-07 00:39:24

标签: reactjs react-router

人。我正在学习如何使用React Router将React与Express集成在一起,并且在验证用户身份时遇到了问题。我正在尝试使用更高阶的组件根据用户的授权状态有条件地呈现受保护的路由。

const ProtectedRoute = ({ component: Component, ...rest }) => {
  return (
    <Route
      {...rest}
      render={props => {
        if (!AUTHORIZED) {
          return <Redirect to="/login" />;
        }
        return <Component {...props} />;
      }}
    />
  );
};

我遇到的问题是在if (!AUTHORIZED)语句中。我正在使用Passport在Express服务器端处理身份验证,并且已经设置了一个端点来检索用户信息和授权状态,但是我不知道如何在页面呈现之前获取对这些数据的访问权限。如果我使用类组件而不是功能组件(也要学习钩子),我认为我可以使用componentWillMount生命周期方法来获取数据,但是我读到这是不好的做法。关于如何从这里前进的任何想法将不胜感激!

***编辑*** 我尝试了几件事以使其正常工作... 我尝试添加一个授权模块来为我获取数据。

class Auth {
  constructor() {
    this.authenticated = false;
  }

  async isAuthenticated() {
    console.log("hitting auth route");
    await fetch("/api/auth")
      .then(res => res.json())
      .then(json => {
        if (json.error) {
          this.authenticated = false;
        }
        this.authenticated = true;
      });
    return this.authenticated;
  }
}

export default new Auth();

我导入模块并插入auth.authenticated()代替占位符AUTHORIZED。由于该函数是异步的,因此将跳过该函数,并且始终会发生重定向。 因此,我需要将await添加到auth.authenticated()中。但是,现在我需要使async更加深入,因此我愚蠢地在async前面添加了props,如下所示: render={async props => { 因此,现在它正在尝试呈现一个Promise对象而不是一个组件,并且我们得到错误Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead. 一路走下去。

1 个答案:

答案 0 :(得分:2)

回答此问题,以防有人遇到类似问题... 我的第一个解决方案是基于Firealem Erko的评论。登录时,我将带有用户ID的变量保存到本地存储中,并在我的组件中引用了该变量。这是一个很好的第一个解决方案,但后来在他的评论中提到的rotimi-best得到了改进。事实证明,您确实可以将道具传递给这些组件,这在我的经验不足的情况下并没有意识到。所以这就是我现在做的方式。最终的解决方案如下:

const ProtectedRoute = ({
  component: Component,
  logged,
  setLogged,
  ...rest
}) => {
  return (
    <Route
      {...rest}
      render={props => {
        if (!logged) {
          return (
            <Redirect
              to={{
                pathname: "/login",
                state: { flashInfo: "Please log in to continue." }
              }}
            />
          );
        } else {
          return <Component {...props} logged={logged} setLogged={setLogged} />;
        }
      }}
    />
  );
};

这是我传递道具的父组件:

function App() {
  let [logged, setLogged] = useState(false);

  useEffect(() => {
    if (window.localStorage.getItem("qrs")) {
      setLogged(true);
    } else {
      setLogged(false);
    }
  }, []);

  return (
    <div className="App">
      <BrowserRouter>
        <Nav logged={logged} setLogged={setLogged} />
        <Switch>
          <ProtectedRoute
            exact
            path="/dashboard"
            component={Dashboard}
            logged={logged}
            setLogged={setLogged}
          />
          <Route
            path="/register"
            exact
            render={props => <Register {...props} logged={logged} />}
          />
          <Route
            path="/login"
            exact
            render={props => (
              <Login {...props} logged={logged} setLogged={setLogged} />
            )}
          />
        </Switch>
      </BrowserRouter>
    </div>
  );
}

感谢所有评论者的建议!