响应如何使用私有路由处理联合登录重定向

时间:2021-04-01 13:03:30

标签: reactjs react-router react-router-dom aws-amplify

我使用 AWS Amplify 通过电子邮件/密码和 Google 联合登录进行身份验证。我还利用 Hub API 来侦听身份验证更改。当用户使用电子邮件/密码登录时,我们的用户将被重定向到私有路由,一切都按预期进行。当用户使用 Google 联合登录名登录时,页面重定向到 google,然后我的私有路由捕获此登录名并将其重定向回登录。

重定向到 google 进行登录后,Amplify 假设将我们发送回 /PrivateRoute

我尝试使用 <Route>exact 调整我的 strict 属性,但问题仍然存在。

这是我使用身份验证处理私有路由的标准方式,但我第一次使用 Amplify 联合登录。有什么建议吗?

参见下面的示例代码:

aws-exports.js

...
cont awsConfig = {
...
oauth: {
  ...
  redirectSignIn: "http://localhost:3000/PrivateRoute
  redirectSignOut: "http://localhost:3000/SignIn
  ...
}

PrivateRoute.js

import React, { useContext } from "react";
import { Route, Redirect } from "react-router-dom";
import { AuthContext } from "../AuthContextProvider.js";

const PrivateRoute = (props) => {
  const { component: Component, ...rest } = props;
  const user = useContext(AuthContext);
  console.log(user)
  return (
    <Route
      {...rest}
      render={(matchProps) =>
        user ? <Component {...matchProps} /> : <Redirect to="/SignIn" />
      }
    />
  );
};

export default PrivateRoute;

AuthContextProvider.js

import React, { useState, useEffect } from "react";
import Amplify, { Auth, Hub } from "aws-amplify";

const AuthContext = React.createContext();

const AuthContextProvider = (props) => {
  const [user, setUser] = useState(null);

  useEffect(() => {
    Amplify.configure(props.awsconfig);

    Hub.listen("auth", ({ payload: { event, data } }) => {
      switch (event) {
        case "signIn":
          setUser(data);
          break;
        case "signOut":
          setUser(null);
          break;
        default:
          break;
      }
    });

    Auth.currentAuthenticatedUser()
      .then((user) => setUser(user))
      .catch((user) => setUser(null));
  }, []);

  return (
    <AuthContext.Provider value={user}>{props.children}</AuthContext.Provider>
  );
};

export default AuthContextProvider;
export { AuthContext };

SignIn.js

...
import { Auth } from "aws-amplify";
import { AuthContext } from "../AuthContextProvider.js";
...

const SignIn = ({ config }) => {
...
  const user = useContext(AuthContext);

  async function handleSignIn() {
    try {
      const user = await Auth.signIn(email, password);
      if (user) {
        history.push(redirectPath);
      }
    } catch (error) {
      console.log("error signing in:", error);
    }
  }

  
  if (user) {
    return <Redirect to={redirectPath} />;
  }

  return (

    <Button onClick={() => handleSignIn()}
       Email/PW Log In
    </Button>
    <Button onClick={() => Auth.federatedSignIn({ provider: "Google" })}
       Google Log In
    </Button>
  );
};

1 个答案:

答案 0 :(得分:0)

这个解决方案的答案现在显而易见。

在我的 AuthContextProvider.js 中,我需要在加载依赖组件之前等待我的异步授权。

通过添加以下状态:

const [isLoadingUser, setIsLoadingUser] = useState(true);

然后我可以设置:

Auth.currentAuthenticatedUser()
      .then((user) => {
        setUser(user)
        setIsLoadingUser(false) // set bool upon completion
      })
      .catch((user) => {
        setUser(null)
        setIsLoadingUser(false)  // set bool upon failure
      });
  }, []);

最后,如果我的整个应用程序都在身份验证之后,我可以改为返回一个加载组件:

if (isLoadingUser) {
    return (<LoadingUser />)
}