我正在使用与用户打交道的firebase auth构建一个Flutter应用程序。我的目标是通过允许电子邮件注册和验证来简化用户的入职体验,而不必强迫用户退出并再次登录以使用全部功能。在与实际用户进行测试之前,这正是我所配置的,但是绝大多数反馈是,它会中断甚至可能导致用户完全放弃身份验证流程。该应用程序只需检测出身份验证状态的这一变化,而无需注销。
我尝试过的内容
我在main.dart中使用以下内容在整个应用程序中提供身份验证状态:
StreamProvider < FirebaseUser > .value(
value: FirebaseAuth.instance.onAuthStateChanged,
),
我用
user1 = Provider.of<FirebaseUser>(context, listen: true);
在各个页面中访问,并访问三元表达式中的不同属性(如user1.isEmailVerified),以确定向用户显示的内容。
我知道onAuthStateChanged不会被要求进行电子邮件验证中的更改,仅用于用户登录和注销,如this question的已接受答案中所述,但是我仍然需要更新确定用户验证电子邮件时显示的用户界面。我已选择使用“完成电子邮件验证”按钮,该按钮将在验证后手动触发检查并使用新值重新加载用户配置文件。这是该按钮的代码:
() async {
// 1
FirebaseUser user =
await _firebaseAuth.currentUser();
print(user.isEmailVerified); // returns false
// 2
await user.getIdToken();
print(user.isEmailVerified);// returns false
// 3
await user.reload();
print(user.isEmailVerified);// returns false
//4
user = await _firebaseAuth.currentUser();
print(user.isEmailVerified);// this finally returns true
}
其中最终的_firebaseAuth = FirebaseAuth.instance;
我注意到,两次调用.currentUser()(在reload()之前和之后)是唯一真正返回.isEmailVerified属性为true而不注销并重新登录的唯一方法。这是我在{ {3}}。
如果再次按下该按钮,则以上所有打印语句将返回true。
问题
那很好,但是问题在于存储FirebaseUser流的user1变量即使在此之后也不会更改或更新,因此,即使用户电子邮件已通过验证,UI仍保持不变。我知道这是因为我在代码中放置了以下检查:
print('this one is from the stream:');
print(user1.isEmailVerified);
即使在按钮功能主体中,user.isEmailVerified返回true时,它仍然返回false。
我试图像这样在按钮内调用设置状态:
setState(() {user1 = user; });
但是,即使我试图将user1的值设置为从按钮的函数派生的新值,user1的值仍保持不变,并且仍对user1.isEmailVerified返回false!
这让我感到非常沮丧,因为我感觉自己非常接近,但我只是不知道如何在整个应用程序甚至在一个屏幕上刷新user1(firebase用户流)的值。这应该更直接。
我注意到验证电子邮件后按热重载并按上面的按钮将在整个调试过程中在整个应用程序中自动显示更新的.isEmailVerified值。有没有一种方法可以以编程方式触发热重载所使用的相同类型的重建,该重建也将刷新Firebase用户流数据而无需注销并重新登录?也许这就是答案所在,但我不知道该如何进行。
任何帮助将不胜感激。
答案 0 :(得分:1)
代替 onAuthStateChanged
,您可以使用 userChanges
流
提供有关所有用户更改的事件,例如何时链接、取消链接以及何时对用户配置文件进行更新。此 Stream 的目的是为了收听用户的实时更新,而无需手动调用 [reload]
见https://firebase.flutter.dev/docs/auth/usage/#authentication-state
答案 1 :(得分:1)
我也遇到了这个问题并在以下人员的帮助下得到解决:
await user.reload();
user = await _auth.currentUser();
user.isEmailVerified => now it is true
答案 2 :(得分:0)
FirebaseAuth Flutter插件为Stream提供了 onAuthStateChanged,当用户获得更新时非常有用 登录或注销,但当用户登录时无法提供更新 数据本身会发生变化。一个常见的问题是,当我们要检测 用户刚刚验证了他的电子邮件地址,换句话说,获得 FirebaseUser.isEmailVerified更改了其值,因为此值已更新 服务器端而不是推送到应用程序。
FirebaseAuth.currentUser()将仅检测本地对 用户,但是如果在服务器端进行了任何更改,它将无法检测到, 除非先调用FirebaseUser.reload()然后再调用 FirebaseAuth.currentUser()再次获取重新加载的用户,但仍然 此用户不会由onAuthStateChanged发出。
这可以帮助您: https://pub.dev/packages/firebase_user_stream
您将找到手动解决方案,也可以使用该软件包。
答案 3 :(得分:0)
在试图弄清楚user.reload()为什么不更新我的用户的电子邮件验证状态时,我遇到了您的问题。感谢您建议再次获取currentUser,该方法可以正常工作。
为回答您的问题,我使用rxdart的BehaviorSubject来存储我的FirebaseUser,因此我可以使用StreamBuilder从应用程序中的任何位置获取有关用户更改的通知:
final BehaviorSubject<FirebaseUser> firebaseUser = new BehaviorSubject<FirebaseUser>();
userListener = FirebaseAuth.instance.onAuthStateChanged.listen((user) {
if (user == null) {
userSignedOut();
}
else if (currentFirebaseUser == null || user.uid != currentFirebaseUser.uid) {
processNewUser(user);
}
firebaseUser.add(user);
});
答案 4 :(得分:0)
身份验证状态更改侦听器对我不起作用。即使用户验证了电子邮件,字段isEmailVerified
仍为false
。
我的解决方法: 从假设用户离开应用程序以验证其电子邮件(这意味着应用程序已已暂停)开始,然后他在验证应用程序(应用程序恢复)后返回了该应用程序。 / p>
我所做的是将WidgetsBinding
附加到相关的有状态小部件,如果要验证电子邮件,我想在其中显示(但可以在其他地方完成)。这涉及两个步骤。
第一步是附加绑定:
@override
void initState() {
WidgetsBinding.instance.addObserver(this);
super.initState();
}
@override
void dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
第二步是覆盖didChangeAppLifecycleState
以重新加载用户。我创建了一个函数,该函数可以重新加载并设置新的firebaseUser对象
void didChangeAppLifecycleState(AppLifecycleState state) {
if (state == AppLifecycleState.resumed && !firebaseUser.isEmailVerified)
refreshFirebaseUser().then((value) => setState(() {}));
super.didChangeAppLifecycleState(state);
}
Future<void> refreshFirebaseUser() async {
await firebaseUser.reload();
firebaseUser = FirebaseAuth.instance.currentUser;
}
因此,这基本上是在每次用户返回应用程序时重新加载firebase用户对象,而其电子邮件未得到验证。这似乎比我在SO中找到的最佳解决方法更干净,该解决方法包括通过计时器设置和取消重复操作。