加载页面时,Firebase auth.currentUser为null,在页面加载几毫秒后调用authstatechange时,用户加载 [英] Firebase auth.currentUser is null when loading the page, user loaded when authstatechange called after some milli seconds of page load

查看:63
本文介绍了加载页面时,Firebase auth.currentUser为null,在页面加载几毫秒后调用authstatechange时,用户加载的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在将React与Firebase一起使用来开发一个小型Web应用程序. 为了进行身份验证,我使用了上下文API,并且在上下文中添加了登录用户的详细信息.

I am using React with Firebase to develop a small web app. To take care of authentication, I am using context API and inside context I am adding loggedin user details.

AuthProvider.tsx

AuthProvider.tsx

const AuthProvider: React.FC = props => {
  const [state, setState] = useState<IAuthContext>(authInitialState);
  console.log("Inside AuthProvider");
  useEffect(() => {
    auth.onAuthStateChanged( user => {
      console.log("Auth State changed and user is ----->", user);
      if (user) {
        console.log("User value updated to the context")
        setState({
            ...authInitialState,
          isAuthenticated:!!user,
          permissions:[],
          user:user
        });
      }
      const stateChange = {
        ...authInitialState,
        isAuthenticated: !!user,
        user
      };
      // if (!user) {
        return setState(stateChange);
      // }
    });
  }, []);
  console.log("Rendering AuthProvider", state);
  return (
    <AuthContext.Provider value={state}>{props.children}</AuthContext.Provider>
  );
};
export default AuthProvider;

AuthConsumer.tsx

AuthConsumer.tsx

const withAuthContext = (
  Component: React.ComponentClass<any> | React.FunctionComponent<any>
) => {
  console.log("Rendering AuthConsumer for ");
  return (props: any) => (
    <AuthContext.Consumer>
      {context => <Component {...props} context={context} />}
    </AuthContext.Consumer>
  );
};

export default withAuthContext;

PrivateRoute.tsx

PrivateRoute.tsx

interface PrivateRouteProps extends RouteProps {
    // tslint:disable-next-line:no-any
    component: any;
    context: IAuthContext;
}

const PrivateRoute = (props: PrivateRouteProps) => {
    const { component: Component, context: IAuthContext, ...rest } = props;
    console.log("Private route for ", props);
    return (
        <Route
            {...rest}
            render={(routeProps) =>
                props.context.isAuthenticated ? (
                    <Component {...routeProps} />
                ) : (
                    <Redirect
                        to={{
                            pathname: '/login',
                            state: { from: routeProps.location }
                        }}
                    />
                )
            }
        />
    );
};

export default withAuthContext(PrivateRoute);

App.tsx

App.tsx

return (
        <BrowserRouter>
            <div>
                <Switch>
                    <PublicRoute path="/frame" component={Frame} exact isAuthorized={true}/>
                    <Route path="/login" component={NewLogin} exact isAuthorized={true}/>
                    <PrivateRoute path="/nav" component={NavigationBar} exact/>
                    <PrivateRoute path="/dashboard" component={AnalyticsDashBoard} exact/>
                    <PrivateRoute path="/subscription" component={OrderSuccess} exact/>
                    <PrivateRoute path="/onboarding" component={OnBoarding} exact/>
                </Switch>
            </div>
        </BrowserRouter>
    );

用户已经登录,并且会话持久性设置为本地. 问题是,当我尝试本地主机/订阅(这是一条私有路由)时,context.isAuthenticated为false,因为尚未触发"onAuthStateChanged"观察者,因此它进入了登录页面,但是在几毫秒内,authStateChange被触发并设置了上下文,但它没有用,因为privateroute认为用户未登录,因此应用程序已经导航到登录状态. 我想了解如何解决此问题的知识.

The user is already loggedin, and session persistence set to local. The problem is, when I try localhost/subscription, which is a private route, context.isAuthenticated is false since "onAuthStateChanged" observer is not triggered yet, so its going to login page, but in few milliseconds, authStateChange triggered and context set, but its no use since application already navigated to login since privateroute thought user not loggedin. I would like to get knowledge on how to overcome this issue.

推荐答案

页面加载后,Firebase将从本地存储中还原用户的凭据,并与服务器一起检查它们是否仍然有效.由于这是对服务器的调用,因此可能要花费一些时间,并且是异步发生的.这就是firebase.auth().currentUsernull直到onAuthStateChanged触发是正常的原因.

When the page loads Firebase restores the user's credentials from local storage and checks with the server whether they are still valid. Since this is a call to the server, it may take some time and happens asynchronously. This is the reason it is normal that firebase.auth().currentUser is null until onAuthStateChanged fires.

您遇到的问题是firebase.auth().currentUser可能是null的原因有多种:

The problem you have is that there are multiple reasons firebase.auth().currentUser can be null:

  1. firebase.auth().currentUsernull,因为客户端刚刚加载并且仍在与服务器一起检查凭据.
  2. firebase.auth().currentUsernull,因为客户端已针对服务器检查了凭据,并且客户端未登录.
  3. firebase.auth().currentUsernull,因为用户从未登录过,因此没有要检查的凭据.
  1. firebase.auth().currentUser is null because the client just loaded and it's still checking the credentials with the server.
  2. firebase.auth().currentUser is null because the client checked the credentials against the server and the client isn't logged in.
  3. firebase.auth().currentUser is null because the user never signed in, so there are no credentials to check.

您要在情况2和3中导航,而不是情况1.

You want to navigate in case 2 and 3, but not case 1.

典型的解决方案是在第一次触发onAuthStateChanged之前不处理导航.此时,您可以确定已针对服务器检查了凭据,或者没有要检查的凭据,在两种情况下,您都希望导航到登录页面.

The typical solution is to not handle navigation until the first time onAuthStateChanged has fired. At that point you can be certain that the credentials were checked against the server, or that there were no credentials to check, in both of which cases you'll want to navigate to the sign-in page.

另一个加快速度的方法是,当用户首次登录时,自己将一个小令牌存储在本地存储中,然后在应用加载时读取该令牌.如果存在令牌,则可以区分情况1和情况3,并用它稍早导航到正确的页面.

An additional option to speed this up is to store a small token in local storage yourself when the user signs in for the first time, and then read that when the app loads. If the token is present you can distinguish between case 1 and 3, and use that to navigate to the correct page a bit sooner.

有关此示例,请参阅有关构建移动Web应用的I/O讨论.

For an example of this, see this I/O talk about Architecting Mobile Web Apps.

这篇关于加载页面时,Firebase auth.currentUser为null,在页面加载几毫秒后调用authstatechange时,用户加载的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆