2

我目前正在开发一个使用带有 Passport.js 的 MERN 堆栈进行身份验证的应用程序,特别是 Google OAuth2 策略。我当前的应用程序具有简单的登录功能,可以从客户端重定向到 Google 同意页面并返回到服务器的重定向 url,然后应该重定向到客户端的主应用程序。我很确定这就是你在服务器端需要做的所有事情,现在我对如何在 React Router 端处理这个有点困惑。

所以首先,我的公共路由中有我的谷歌登录按钮,然后点击服务器中触发谷歌 OAuth 的端点

class Public extends Component {
    render() {
        return (
            <div>
                <h1>Public Route</h1>
                <a href="http://localhost:5000/api/auth/google">Sign In</a>
            </div>
        )
    }
}

在服务器从localhost:5000/auth/google/redirect 重定向localhost:3000/protected之后,我相信它会回到触发 React 路由器的 App.js

class App extends Component {

    constructor(props) {

        super(props)
        this.state = { authenticated: false }
    }

    componentDidMount() {

        api.get('/auth/user').then(({data}) => {

            if (data) this.setState({authenticated: true})
        }).catch((err) => console.error(err))
    }

    render() {

        const { authenticated } = this.state
        return (
            <div className="App">
                <Switch>
                    <Route exact path='/' component={Public} />
                    <PrivateRoute exact authed={authenticated} path='/app' component={Protected} />
                </Switch>
            </div>
        )
    }
}

这就是事情变得有点混乱的地方。所以我认为它会在 componentDidMount() 之前先渲染,所以经过身份验证的状态仍然是 false,所以 PrivateRoute 将客户端重定向回 l​​ocalhost :3000/并渲染公共路由。毕竟,运行 componentDidMount() 并最终获取用户并且现在身份验证是真的,但是现在为时已晚,因为客户端已经重定向到localhost:3000/所以它不再访问 PrivateRoute。

如果有人想知道,这是我的 PrivateRoute 组件:

const PrivateRoute = ({ component: Component, authed, ...rest }) => (
    <Route { ...rest} render={(props) => authed ? 
        <Component {...props} /> :
        <Redirect to={{pathname: '/'}} />
    } />
)

到目前为止我所做的:

  • 使用 componentWillMount() - 没有区别,而且我相信这很快就会被弃用
  • 使用具有isAuthenticatedlogin()logout()成员的全局身份验证对象。我在我的公共组件中创建了该对象的一个​​实例,并添加了onClick={auth.login}以及 href。但是,onClick 在 href 浏览器重定向之前首先运行,因此它会首先尝试获取用户(即使还没有任何设置),所以isAuthenticated不会设置为 true

提前致谢!

4

1 回答 1

0

我认为在您的 privateRoute 组件本身中进行身份验证检查会更容易,而不是在 App 和 privateRoute 之间拆分。

无论如何,您可以渲染一个“加载屏幕”组件,而不是在用户未通过身份验证时进行重定向,该组件仍然会阻止他们到达受保护的路由。这样,您可以等待 http 请求返回,然后再做出是否允许用户访问或将其重定向回登录页面的最终决定。这是一个例子:

const PrivateRoute = ({ component: Component, ...rest }) => {
    const [isAuthenticated, setAuthenticated] = useState(false);

    useEffect(() => {
        axiosInstance.get('/auth/isauthenticated').then(({ data: { user } }) => {
            if (user) {
                setAuthenticated(true);
            } else {
                window.location = '/menu/login';
            }
        });
    }, []);

    return (isAuthenticated 
              ? <Route {...rest} render={(props) => <Component {...props} />} /> 
              : <p>{'Loading'}</p>;)
}
于 2020-06-22T21:04:26.727 回答