Jak sprawdzić, czy użytkownik jest już zalogowany w Firebase?

104

Używam interfejsu API węzła Firebase w moich plikach javascript do logowania się w Google.

firebase.initializeApp(config);
let provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider);

Działa to dobrze, a użytkownik może zalogować się przy użyciu swoich danych logowania Google. Gdy użytkownik ponownie odwiedza stronę, wyskakujące okienko otwiera się ponownie, ale ponieważ jest już zalogowany, wyskakujące okienko zamyka się bez konieczności jakiejkolwiek interakcji ze strony użytkownika. Czy istnieje sposób, aby sprawdzić, czy jest już zalogowany użytkownik przed wyświetleniem monitu o wyskakujące okienko?

Jophin Joseph
źródło

Odpowiedzi:

115

https://firebase.google.com/docs/auth/web/manage-users

Musisz dodać obserwatora zmiany stanu autoryzacji.

firebase.auth().onAuthStateChanged(function(user) {
  if (user) {
    // User is signed in.
  } else {
    // No user is signed in.
  }
});
bojeil
źródło
3
To jest dla mnie niespójne. stackoverflow.com/questions/39395158/…
Dan P.
2
Czy za pomocą onAuthStateChanged można stwierdzić, czy użytkownik jest nowy?
Brennan
Tak, ale nie do końca onAuthStateChanged. To zostało dodane w 4.6.0: firebase.google.com/support/release-notes/js#4.6.0 Możesz to pobrać z metody logowania lub z currentUser.metadata(czas ostatniego logowania i utworzenia) ...
bojeil
@bojeil Myślę, że istnieje zastrzeżenie dotyczące tej metody. Możesz umieścić ten kod na jednej stronie i będzie on wywoływany nawet wtedy, gdy nie jesteś na tej stronie. Uruchamia się, gdy zmienia się AuthState. Jeśli zmieni się na innych stronach, spowoduje to, że będzie się uruchamiał, gdy nie chcesz. Przynajmniej tak się teraz ze mną dzieje.
thevengefulco
1
Spowoduje to wykrycie zdarzeń logowania na innych kartach. Działa zgodnie z przeznaczeniem. Firebase Auth propaguje zdarzenia logowania w oknach.
bojeil
84

Możesz również sprawdzić, czy istnieje currentUser

var user = firebase.auth().currentUser;

if (user) {
  // User is signed in.
} else {
  // No user is signed in.
}
Daniel Passos
źródło
8
To zwraca dla mnie wartość null nawet po natychmiastowym zalogowaniu.
Aarmora
8
To dziwne, u mnie działa, może problem polega na tym, że auth jest async, a _ currentUser_ nie został jeszcze zaktualizowany.
Daniel Passos,
1
Z dokumentu docs: currentUser może mieć również wartość null, ponieważ obiekt auth nie zakończył inicjalizacji. Jeśli używasz obserwatora do śledzenia stanu logowania użytkownika, nie musisz zajmować się tą sprawą.
cheshireoctopus
Nie możesz na tym polegać. Zobacz oficjalne dokumenty: „Są pewne przypadki, w których getCurrentUser zwróci wartość różną od null ...”
Andrew
Jeśli otrzymujesz wartość null, prawdopodobnie dlatego, że nie został jeszcze zainicjowany.
Arnaldo Capo
28

Nie można stwierdzić, czy użytkownik zostanie podpisany, gdy strona zacznie się ładować, jednak istnieje obejście.

Możesz zapamiętać ostatni stan autoryzacji w localStorage, aby zachować go między sesjami i między kartami.

Następnie, gdy strona zacznie się ładować, możesz optymistycznie założyć, że użytkownik zostanie automatycznie ponownie zalogowany i odłóż okno dialogowe, aż będziesz mieć pewność (tj. Po onAuthStateChangedpożarach). W przeciwnym razie, jeśli localStorageklucz jest pusty, możesz od razu wyświetlić okno dialogowe.

onAuthStateChangedZdarzenie Firebase zostanie uruchomione po około 2 sekundach od załadowania strony.

// User signed out in previous session, show dialog immediately because there will be no auto-login
if (!localStorage.getItem('myPage.expectSignIn')) showDialog() // or redirect to sign-in page

firebase.auth().onAuthStateChanged(user => {
  if (user) {
    // User just signed in, we should not display dialog next time because of firebase auto-login
    localStorage.setItem('myPage.expectSignIn', '1')
  } else {
    // User just signed-out or auto-login failed, we will show sign-in form immediately the next time he loads the page
    localStorage.removeItem('myPage.expectSignIn')

    // Here implement logic to trigger the login dialog or redirect to sign-in page, if necessary. Don't redirect if dialog is already visible.
    // e.g. showDialog()
  }
})



Używam tego z React i React -routerem . Umieściłem powyższy kod w componentDidMountmoim głównym składniku aplikacji. Tam, w renderowaniu, mam trochęPrivateRoutes

<Router>
  <Switch>
    <PrivateRoute
      exact path={routes.DASHBOARD}
      component={pages.Dashboard}
    />
...

I tak jest zaimplementowana moja PrivateRoute:

export default function PrivateRoute(props) {
  return firebase.auth().currentUser != null
    ? <Route {...props}/>
    : localStorage.getItem('myPage.expectSignIn')
      // if user is expected to sign in automatically, display Spinner, otherwise redirect to login page.
      ? <Spinner centered size={400}/>
      : (
        <>
          Redirecting to sign in page.
          { location.replace(`/login?from=${props.path}`) }
        </>
      )
}

    // Using router Redirect instead of location.replace
    // <Redirect
    //   from={props.path}
    //   to={{pathname: routes.SIGN_IN, state: {from: props.path}}}
    // />
Qwerty
źródło
Myślisz, że mógłbyś mi w tym pomóc? Wypróbowałem przekierowanie automatycznego logowania, które masz u góry odpowiedzi, a teraz nie mogę go usunąć. Całkowicie wyczyściłem pamięć lokalną i nadal nie mogę uzyskać dostępu do mojej witryny Firebase wylogowanej z powodu ciągłych przekierowań.
hego64
@ hego64 Czy faktycznie wylogowałeś się z aplikacji Firebase? To rozwiązanie nie wymaga logowania. Pozwala tylko na pominięcie formularza logowania, jeśli użytkownik nie wylogował się w poprzedniej sesji. / EDIT: Czy jesteś w pętli przekierowań? Zaktualizuję odpowiedź.
Qwerty
Tak, powinienem był być bardziej jasny, utknąłem w pętli przekierowań. Wylogowywałem się i zamiast wracać do aplikacji, wracałem prosto do strony logowania. Udało mi się to naprawić, cofając się do poprzedniego wdrożenia, ale poza tym nie byłem pewien, co zrobić, aby rozwiązać problem.
hego64
1
@ hego64 Użytkownicy, którzy nie są zalogowani, nie powinni mieć możliwości swobodnego poruszania się, więc przekierowanie do strony logowania jest poprawne, ale jeśli istnieją trasy, które są dostępne bez uwierzytelniania, należy przenieść logikę do routera lub zamiast tego określone trasy, podobnie jak w moim przykładzie opakowania PrivateRoute. Jeśli więc użytkownik znajduje się na stronie z ograniczeniami i się wyloguje, zostanie przekierowany na stronę logowania. Twoje inne trasy nie będą miały tej logiki zaimplementowanej.
Qwerty
Utknąłem na tym trochę ... ta metoda działa całkiem nieźle. Dziękuję Ci.
spetz83
17

W tym scenariuszu nie ma potrzeby używania funkcji onAuthStateChanged ().

Możesz łatwo wykryć, czy użytkownik jest zalogowany, czy nie, wykonując:

var user = firebase.auth().currentUser;

Dla tych, którzy borykają się z problemem „zwracającego null”, dzieje się tak tylko dlatego, że nie czekasz na zakończenie połączenia z bazą firebase.

Załóżmy, że wykonujesz akcję logowania na stronie A, a następnie wywołujesz stronę B, na stronie B możesz wywołać następujący kod JS, aby przetestować oczekiwane zachowanie:

  var config = {
    apiKey: "....",
    authDomain: "...",
    databaseURL: "...",
    projectId: "..",
    storageBucket: "..",
    messagingSenderId: ".."
  };
  firebase.initializeApp(config);

    $( document ).ready(function() {
        console.log( "testing.." );
        var user = firebase.auth().currentUser;
        console.log(user);
    });

Jeśli użytkownik jest zalogowany, „var user” będzie zawierał oczekiwany ładunek JSON, jeśli nie, to będzie po prostu „null”

I to wszystko, czego potrzebujesz.

pozdrowienia

Daniel Vukasovich
źródło
3
@Mauricio Silvestre czy to jest? Korzystanie firebase.auth.currentUserzwraca wartość undefined, czy nie jestem tylko po zalogowaniu auth () zwraca poprawny wynik po zalogowaniu się..
tsujp
5

Innym sposobem jest użycie tego samego, czego używa Firebase.

Na przykład, gdy użytkownik się loguje, Firebase przechowuje poniższe szczegóły w pamięci lokalnej. Gdy użytkownik wraca na stronę, Firebase używa tej samej metody, aby określić, czy użytkownik powinien zalogować się automatycznie.

wprowadź opis obrazu tutaj

UWAGA: ponieważ nie jest to wymienione ani zalecane przez firebase. Możesz nazwać tę metodę nieoficjalnym sposobem robienia tego. Co oznacza, że ​​później, jeśli firebase zmieni swoje wewnętrzne działanie, ta metoda może nie działać. Krótko mówiąc. Używaj na własne ryzyko! :)

ravish.hacker
źródło
5

To działa:

async function IsLoggedIn(): Promise<boolean> {
  try {
    await new Promise((resolve, reject) =>
      app.auth().onAuthStateChanged(
        user => {
          if (user) {
            // User is signed in.
            resolve(user)
          } else {
            // No user is signed in.
            reject('no user logged in')
          }
        },
        // Prevent console error
        error => reject(error)
      )
    )
    return true
  } catch (error) {
    return false
  }
}
Ben Winding
źródło
1

Jeśli pozwalasz anonimowych, jak i tych, zalogować się za pomocą poczty elektronicznej można użyć firebase.auth().currentUser.isAnonymous, który powróci albo truealbo false.

maudulus
źródło
-3

Najpierw zaimportuj następujące elementy

import Firebase
import FirebaseAuth

Następnie

    // Check if logged in
    if (Auth.auth().currentUser != null) {
      // User is logged in   
    }else{
      // User is not logged in
    }
Daniel
źródło