Firebase auth.currentUser имеет значение null при загрузке страницы, пользователь загружается при вызове authstatechange после нескольких миллисекунд загрузки страницы - PullRequest
0 голосов
/ 10 февраля 2020

Я использую React с Firebase для разработки небольшого веб-приложения. Чтобы позаботиться об аутентификации, я использую контекстный API, а внутри контекста добавляю данные пользователя, вошедшего в систему.

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

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

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

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>
    );

пользователь уже вошел в систему, а постоянство сеанса установлено на локальное. Проблема в том, что когда я пытаюсь использовать localhost / subscription, который является частным маршрутом, context.isAuthenticated имеет значение false, поскольку наблюдатель «onAuthStateChanged» еще не запущен, поэтому он собирается перейти на страницу входа, но через несколько миллисекунд, authStateChange сработал и контекст установился, но это бесполезно, так как приложение уже перешло к входу в систему, так как privateroute думал, что пользователь не залогинен Я хотел бы получить знания о том, как преодолеть эту проблему.

1 Ответ

3 голосов
/ 10 февраля 2020

Когда страница загружается, Firebase восстанавливает учетные данные пользователя из локального хранилища и проверяет у сервера, действительны ли они по-прежнему. Поскольку это вызов сервера, это может занять некоторое время и происходит асинхронно. Это причина, по которой firebase.auth().currentUser является null до тех пор, пока не сработает onAuthStateChanged.

Проблема, с которой вы столкнулись, состоит в том, что существует множество причин, по которым firebase.auth().currentUser может быть null:

  1. firebase.auth().currentUser - это null, потому что клиент только что загрузился, и он все еще проверяет учетные данные на сервере.
  2. firebase.auth().currentUser - это null, потому что клиент проверил учетные данные на сервере и клиент не вошел в систему.
  3. firebase.auth().currentUser равен null, потому что пользователь никогда не входил в систему, поэтому нет учетных данных для проверки.

Вы хотите перейти в случаи 2 и 3, но не случай 1.

Типичное решение состоит в том, чтобы не обрабатывать навигацию до тех пор, пока не будет запущен onAuthStateChanged в первый раз. В этот момент вы можете быть уверены, что учетные данные были проверены на сервере или что учетные данные не были проверены, в обоих случаях вам нужно перейти на страницу входа.


Дополнительная опция, позволяющая ускорить это, - это сохранить небольшой токен в локальном хранилище самостоятельно при первом входе пользователя в систему, а затем прочитать его при загрузке приложения. Если токен присутствует, вы можете различить guish между вариантами 1 и 3 и использовать его, чтобы перейти к правильной странице немного раньше.

Пример этого см. В этом I / O поговорим о Архитектура мобильных веб-приложений .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...