有时 firebase.auth().onAuthStateChanged 在我刷新页面时返回 null 用户

Posted

技术标签:

【中文标题】有时 firebase.auth().onAuthStateChanged 在我刷新页面时返回 null 用户【英文标题】:Sometimes firebase.auth().onAuthStateChanged returns user of null when I refresh the page 【发布时间】:2018-11-13 23:34:13 【问题描述】:

前提条件

$npm install --save firebase@4.11.0

问题

我在我的 Web 应用程序上使用 firebase 身份验证。 在我的应用程序中,我为客户端 js 实现了onAuthStateChanged,如下所示。

firebase.auth().onAuthStateChanged((user) => 
  if(user) 
    //logged in
   else 
    //do sth
  
);

登录后,我确认此方法将返回实际用户obj,但如果我刷新页面,则用户可能为空。 奇怪的是,有时用户不会为空。 恐怕调用onAuthStateChanged会有一些限制,但目前我不知道。

我应该如何处理这个问题?

更新

让我分享我的最小示例。

我的应用正在使用 express.js。 有两个 URL,如下所示。 /login /main

在登录页面中,我实现了身份验证方法。 如果登录成功完成,则用户将被重定向到'/main'。

//login.js
import firebase from 'firebase';
var config = ...;
firebase.initializeApp(config);

var provider = new firebase.auth.GoogleAuthProvider();
firebase.auth().signInWithPopup(provider)
.then((result) => 
  return result.user.getIdToken(true);
).then((idToken) => 
  if(idToken) 
    location.href = '/main';
  
);

在主页面中,没有登录方法。 main.js 只是检查用户是否登录。

//main.js
import firebase from 'firebase';
var config = ...;
firebase.initializeApp(config);

firebase.auth().onAuthStateChanged((user) => 
  if (user) 
    //initialize main page.
   else 
    location.href = '/login';
  

我认为登录状态存储在 Web 浏览器的 LocalStorage 中。 这意味着,在完成 main.js 的加载后,onAuthStateChanged 将使用用户信息自动触发,但不会像我预期的那样工作。 我确信登录信息的持久性是正确的,因为官方文档说默认设置是 LOCAL 用于 web 客户端。

https://firebase.google.com/docs/auth/web/auth-state-persistence

我的问题

我应该用另一种方式实现 onAuthStateChanged 吗? 重新加载后如何确保用户已登录?

例如

import $ from 'jquery';
$(document).on('ready', () => 
  onAuthStateChanged((user) => ...);
);

或者你能告诉我正确的方法吗?

解决方法

如果返回 null,我决定删除会话并设置重定向到登录页面。这不是解决方案,而是当前的解决方法...

【问题讨论】:

.onAuthStateChanged 是异步的,在页面加载/刷新时为微秒解析 null。这就是它的工作原理。您可以将 loader 的 gif 变灰或放置。 你的意思是说,在重新加载后,第一个onAuthStateChanged 事件将被空用户触发,几秒钟后该事件将被实际用户信息重新触发?我实现了加载 gif 10 秒,直到加载完成,就像你提到的那样,但是,不幸的是,我的 onAuthStateChanged 只被空用户触发一次...... 在另一个浏览器上尝试网络应用/您的应用。我注意到,例如,如果您将 Firefox 设置为从不记住历史记录(可能是关闭存储),我的身份验证将失败且没有任何有意义的错误。 您是否在使用主机重写?延迟对我来说非常重要,但如果我不使用托管重写,它就会完全消失。 【参考方案1】:

它有时为 null 有时不为 null 的事实可能表明存在异步问题。您是否在上面的 if 语句中进行检查?所有对用户的引用都应该在回调中。如果一切顺利,则可能检查身份验证是否已正确启动。

【讨论】:

感谢您的评论。是的,我确定用户 obj 仅在 onAuthStateChanged 方法中被引用。【参考方案2】:

你没有打电话给onAuthStateChanged。相反,您是在告诉 Firebase 在身份验证状态更改时调用 ,这可能会在重新加载页面时发生几次

当页面正在加载并且之前有用户登录时,身份验证状态可能会更改几次,而客户端正在确定用户的身份验证状态是否仍然有效。因此,您可能在看到实际登录用户的最终通话之前看到没有用户的通话。

【讨论】:

感谢您的建议。就我而言,无论用户是否登录,firebase 都不能保证在重新加载页面时调用 onAuthStateChanged ......我的理解是否正确?如果是这样,我是否应该在清楚地完成重新加载后调用其他方法,如auth.currentUser 您的onAuthStateChanged 回调将在页面加载时以当前状态调用,然后在每个阶段更改时调用。这正是它的目的。如果您更新您的问题以包含minimal complete reproduction of the problem,那么提供更多帮助会更容易,因为现在我只能说听起来事情正在按预期工作。 我已根据您的建议更新了我的问题。如果您检查我的更新,我将不胜感激。 ...我实际上只是测试了 w console.log 并且 firebase.auth() 最初并没有像以前那样使用 null 触发。它仍然异步触发,我的 UI 仍然闪烁。 ...proly 我的编码应该更新以静音闪烁(例如登录按钮display:none vs photoURL <img> acct menu)... 嗯,我觉得我的应用程序的行为很有趣(或奇怪)。我的理解是:除非用户删除他的身份验证状态或本地存储,否则不会返回 Null。最后,我发现删除我的 chrome 上的任何缓存,然后问题暂时不会出现,但是,有时这种情况仍然可能发生。因此,如果身份验证失败,我决定删除会话并将重定向设置为登录页面。你的建议对我帮助很大。谢谢!【参考方案3】:

onAuthStateChanged 是 firebase 文档中所述的观察者,当身份验证状态发生变化时触发,例如用户登录、退出、密码更改。要检查用户是否登录,您应该使用 firebase.auth().currentUser 这将为您提供当前登录的用户。正如您所说,您的状态是本地 firebase.auth().currentUser 将始终为您提供用户,除非用户退出。

【讨论】:

以上是关于有时 firebase.auth().onAuthStateChanged 在我刷新页面时返回 null 用户的主要内容,如果未能解决你的问题,请参考以下文章

致命错误:找不到模块“firebase_auth”@import firebase_auth

GeneratedPluginConstraint,致命错误:找不到模块“firebase_auth”@import firebase_auth;

firebase.auth().currentUser 为空

如何在 firebase-functions 中使用 firebase.auth()?

错误:名称“用户”在库“package:firebase_auth/firebase_auth.dart”和“package:quizmaker/models/user.dart”中定义

使用自己的身份验证服务器的firebase-auth模块和firebase-common-auth的重复