Flutter接入Firebase Auth时未验证邮箱用户仍可访问应用如何解决
解决方案
1. 扩展用户模型
首先给你的Users类新增isEmailVerified字段,用于存储邮箱验证状态:
class Users { final String uid; final bool isEmailVerified; // 新增字段 Users({required this.uid, required this.isEmailVerified}); }
2. 调整AuthService逻辑
需要做三处核心修改:
- 修改用户数据转换方法,带入验证状态
- 注册成功后自动发送验证邮件
- 替换监听流为
userChanges()(authStateChanges仅监听登录/登出状态变化,不会同步邮箱验证状态的更新) - 新增刷新用户验证状态、重发验证邮件的工具方法
修改后的AuthService代码:
class AuthService { final FirebaseAuth _auth = FirebaseAuth.instance; final googleSignIn = GoogleSignIn(); GoogleSignInAccount? _user; // 修改用户转换方法,带入验证状态 Users? _userFromFirebaseUser(User? user) { return user != null ? Users(uid: user.uid, isEmailVerified: user.emailVerified) : null; } // 替换为userChanges流,可监听邮箱验证状态更新 Stream<Users?> get user { return _auth.userChanges().map(_userFromFirebaseUser); } //注册 with 邮箱&密码 Future registerWithEmailAndPassword(String email, String password) async { try { UserCredential result = await _auth.createUserWithEmailAndPassword( email: email, password: password); User? user = result.user; if (user != null && !user.emailVerified) { // 注册成功后自动发送验证邮件 await user.sendEmailVerification(); } return _userFromFirebaseUser(user); } catch (e) { print(e.toString()); return null; } } // 新增:刷新用户验证状态(用户点击验证链接回到APP后调用) Future reloadUser() async { try { await _auth.currentUser?.reload(); } catch (e) { print(e.toString()); } } // 新增:重发验证邮件 Future resendVerificationEmail() async { try { await _auth.currentUser?.sendEmailVerification(); } catch (e) { print(e.toString()); } } //sign out Future signOut() async { try { return await _auth.signOut(); } catch (e) { print(e.toString()); return null; } } }
3. 修改Wrapper路由判断逻辑
在原有登录状态判断的基础上,新增邮箱验证状态判断,未验证的用户跳转至验证提示页:
class Wrapper extends StatelessWidget { const Wrapper({Key? key}) : super(key: key); @override Widget build(BuildContext context) { final user = Provider.of<Users?>(context); if (user == null) { // 未登录跳转认证页 return Authenticate(); } else if (!user.isEmailVerified) { // 已登录但未验证邮箱,跳转验证提示页 return EmailVerificationPage(); } else { // 验证通过跳转首页 return Home(); } } }
4. 实现邮箱验证提示页
新增EmailVerificationPage组件,提示用户查收验证邮件,同时提供重发邮件、手动刷新验证状态的按钮:
class EmailVerificationPage extends StatelessWidget { final AuthService _auth = AuthService(); EmailVerificationPage({super.key}); @override Widget build(BuildContext context) { return Scaffold( body: Center( child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ const Text("我们已向你的注册邮箱发送了验证链接,请点击链接完成验证后再进入应用"), const SizedBox(height: 20), ElevatedButton( onPressed: () async { await _auth.reloadUser(); }, child: const Text("我已完成验证,刷新状态"), ), TextButton( onPressed: () async { await _auth.resendVerificationEmail(); ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text("验证邮件已重发"))); }, child: const Text("没收到邮件?重发验证链接"), ), TextButton( onPressed: () async { await _auth.signOut(); }, child: const Text("换个邮箱注册"), ) ], ), ), ); } }
5. 后端安全加固
前端逻辑仅用于用户体验优化,必须同步配置Firebase安全规则,阻止未验证邮箱的用户访问后端资源,示例规则参考:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read, write: if request.auth != null && request.auth.token.email_verified == true; } } }
内容的提问来源于stack exchange,提问作者Mamoudou Kane
相关产品推荐
相关产品推荐

