Como posso detectar se um usuário já está conectado ao Firebase?

102

Estou usando o Firebase node api em meus arquivos javascript para o login do Google.

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

Isso funciona bem e o usuário pode fazer login com suas credenciais do Google. Quando o usuário visita a página novamente, o pop-up é aberto novamente, mas como ele já fez login, o pop-up fecha sem exigir nenhuma interação do usuário. Existe alguma maneira de verificar se já existe um usuário conectado antes de abrir o pop-up?

Jophin Joseph
fonte

Respostas:

113

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

Você tem que adicionar um observador de mudança de estado de autenticação.

firebase.auth().onAuthStateChanged(function(user) {
  if (user) {
    // User is signed in.
  } else {
    // No user is signed in.
  }
});
bojeil
fonte
3
Isso é inconsistente para mim. stackoverflow.com/questions/39395158/…
Dan P.
2
Usando onAuthStateChanged, há uma maneira de saber se um usuário é novo?
Brennan
Sim, mas não completamente onAuthStateChanged. Isso foi adicionado em 4.6.0: firebase.google.com/support/release-notes/js#4.6.0 Você pode obtê-lo no método de currentUser.metadatalogin ou em (hora do último login e hora de criação) ...
bojeil
@bojeil Acho que há uma ressalva nesse método. Você pode colocar esse código em uma página e ele será acionado mesmo quando você não estiver nessa página. Ele é acionado quando o AuthState muda. Se mudar em outras páginas, você efetivamente fará com que seja acionado quando não quiser. Pelo menos, é isso que está acontecendo comigo agora.
thevengefulco
1
Isso detectará eventos de login em outras guias. Funciona como pretendido. O Firebase Auth propaga eventos de login nas janelas.
bojeil
82

Você também pode verificar se há um usuário atual

var user = firebase.auth().currentUser;

if (user) {
  // User is signed in.
} else {
  // No user is signed in.
}
Daniel Passos
fonte
8
Isso está retornando nulo para mim, mesmo após um login imediato.
Aarmora
8
Isso é estranho, funciona para mim, talvez o problema seja porque auth é assíncrono e _ currentUser_ ainda não foi atualizado.
Daniel Passos
1
Nos documentos: currentUser também pode ser nulo porque o objeto auth não concluiu a inicialização. Se você usar um observador para rastrear o status de login do usuário, não será necessário lidar com este caso.
cheshireoctopus
Você não pode confiar nisso. Consulte a documentação oficial: "Existem alguns casos em que getCurrentUser retornará um valor não nulo ..."
Andrew
Se você está obtendo nulo, provavelmente é porque ele ainda não foi inicializado.
Arnaldo Capo
28

Não é possível dizer se um usuário será assinado quando uma página começar a carregar, no entanto, há uma solução alternativa.

Você pode memorizar o último estado de autenticação em localStorage para persisti-lo entre as sessões e entre as guias.

Então, quando a página começar a carregar, você pode assumir de forma otimista que o usuário fará login novamente automaticamente e adiar a caixa de diálogo até que você tenha certeza (ou seja, após os onAuthStateChangeddisparos). Caso contrário, se a localStoragechave estiver vazia, você pode mostrar a caixa de diálogo imediatamente.

O onAuthStateChangedevento firebase será disparado cerca de 2 segundos após o carregamento de uma página.

// 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()
  }
})



Estou usando isso com React e react-router . Eu coloquei o código acima em componentDidMountmeu componente raiz do aplicativo. Lá, no render, eu tenho algunsPrivateRoutes

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

E é assim que meu PrivateRoute é implementado:

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
fonte
Você acha que poderia me ajudar com isso? Tentei o redirecionamento de login automático que você tem na parte superior da sua resposta e agora não consigo removê-lo. Limpei meu armazenamento local completamente e ainda não consigo acessar meu site do Firebase desconectado devido aos redirecionamentos constantes.
hego64
@ hego64 Você realmente se desconectou do aplicativo Firebase? Esta solução não faz o login. Ela só permite pular o formulário de login se o usuário não se desconectar na sessão anterior. / EDIT: Você está em um loop de redirecionamento? Vou atualizar a resposta.
Qwerty
Sim, eu deveria ter sido mais claro, estava preso em um loop de redirecionamento. Eu saía e, em vez de voltar para o aplicativo, era levado de volta para a página de login. Consegui consertar revertendo para uma implantação anterior, mas, fora isso, não tinha certeza do que fazer para corrigir o problema.
hego64
1
@ hego64 Os usuários que não estão conectados não devem ser capazes de circular livremente de qualquer maneira, portanto, redirecionar para a página de login está correto, mas se houver rotas disponíveis sem autenticação, você deverá mover a lógica para o roteador ou rotas específicas, como em meu exemplo de wrapper PrivateRoute. Portanto, se o usuário estiver em uma página restrita e sair, ele será redirecionado para a página de login. Suas outras rotas não terão essa lógica implementada.
Qwerty
Fiquei preso nisso por um tempo ... esse método funciona muito bem. Obrigado.
spetz83
17

Não há necessidade de usar a função onAuthStateChanged () neste cenário.

Você pode detectar facilmente se o usuário está conectado ou não executando:

var user = firebase.auth().currentUser;

Para aqueles que enfrentam o problema de "retornar nulo", isso ocorre porque você não está esperando a conclusão da chamada do firebase.

Vamos supor que você execute a ação de login na página A e, em seguida, invoque a página B, na página B você pode chamar o seguinte código JS para testar o comportamento esperado:

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

Se o usuário estiver logado, "var user" conterá a carga útil JSON esperada; caso contrário, será apenas "nulo"

E isso é tudo que você precisa.

Saudações

Daniel Vukasovich
fonte
3
@Mauricio Silvestre não é? O uso de firebase.auth.currentUserretorna undefined
estando eu conectado
5

Outra maneira é usar a mesma coisa que o firebase usa.

Por exemplo, quando o usuário faz login, o firebase armazena os detalhes abaixo no armazenamento local. Quando o usuário volta à página, o firebase usa o mesmo método para identificar se o usuário deve fazer login automaticamente.

insira a descrição da imagem aqui

ATTN: como isso não está listado nem recomendado pelo firebase. Você pode chamar esse método de maneira não oficial de fazer isso. O que significa que mais tarde, se o firebase alterar seu funcionamento interno, esse método pode não funcionar. Ou em resumo. Use por sua conta e risco! :)

ravish.hacker
fonte
5

Isso funciona:

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
fonte
1

Se você estiver permitindo usuários anônimos, bem como aqueles conectados com e-mail, você pode usar firebase.auth().currentUser.isAnonymous, que retornará trueou false.

maudulus
fonte
-1

usar Firebase.getAuth() . Ele retorna o estado atual do cliente Firebase. Caso contrário, o valor de retorno é nullAqui estão os documentos: https://www.firebase.com/docs/web/api/firebase/getauth.html

Muetzerich
fonte
15
Obsoleto, evitarfirebase.getAuth()
Mazze
-3

Primeiro importe o seguinte

import Firebase
import FirebaseAuth

Então

    // Check if logged in
    if (Auth.auth().currentUser != null) {
      // User is logged in   
    }else{
      // User is not logged in
    }
Daniel
fonte