Flutter基于角色的认证异常:始终停留在SigninPage无法跳转
问题:Flutter Firebase认证后无法根据角色跳转对应页面
开发Flutter毕设应用时,为Admin、Staff、Member、Collector四类用户分配了对应页面,但用户完成认证后始终停留在SigninPage,无法跳转至对应角色页面。
核心问题排查
从代码中可定位两个关键问题:
- 注册时Firestore文档ID与Auth UID不匹配:注册使用
add()方法生成随机文档ID,而getRole通过Auth的UID查询文档,导致查询不到对应数据。 - 注册未写入
role字段:addUserDetailes方法未包含用户角色字段,即使文档存在,查询role时会抛出异常,最终导致角色判断逻辑失效。
解决方案
1. 修复注册逻辑:绑定UID与文档ID并添加role字段
修改注册方法,用Auth用户UID作为Firestore文档ID,同时写入role字段(默认设为member,可根据需求改为用户选择式):
Future signUp() async{ final isValid = formKey.currentState!.validate(); if (!isValid) return; showDialog( context: context, barrierDismissible: false, builder: (context) => const Center(child: CircularProgressIndicator())); try{ // 创建用户并获取UID UserCredential userCredential = await FirebaseAuth.instance.createUserWithEmailAndPassword( email: emailController.text.trim(), password: passwordController.text.trim(), ); String uid = userCredential.user!.uid; // 写入用户数据到Firestore,用UID作为文档ID await addUserDetailes( uid, firstnameController.text.trim(), middlenameController.text.trim(), lastnameController.text.trim(), fulladdressController.text.trim(), civilstatuscontroller.text.trim(), emailController.text.trim(), int.parse(phonenoController.text.trim()), int.parse(ageController.text.trim()), 'member', // 默认角色,可按需修改 ); }on FirebaseAuthException catch (e){ print(e); Utils.showSnackBar(e.message); } navigatorKey.currentState!.popUntil((route) => route.isFirst); } // 更新addUserDetailes方法,接收uid和role参数 Future addUserDetailes(String uid, String firstName, String middleName, String lastName, String fullAddress, String civilStatus, String email, int phoneNumber, int age, String role ) async{ await FirebaseFirestore.instance.collection('users').doc(uid).set({ 'first name': firstName, 'middle name': middleName, 'last name': lastName, 'full address': fullAddress, 'civil status' : civilStatus, 'email': email, 'phone number': phoneNumber, 'age' : age, 'role': role, // 添加角色字段 }); }
2. 统一getRole方法并添加日志排查
删除MainPage中重复的getRole方法,使用全局方法并添加日志辅助排查:
// 全局getRole方法 Future<String> getRole(String id) async { String role = "member"; try { final snapshot = await FirebaseFirestore.instance .collection(FireStoreConstants.users) .doc(id) .get(); print('查询用户文档ID: $id'); if (snapshot.exists) { print('文档存在,数据: ${snapshot.data()}'); // 检查是否存在role字段 if (snapshot.data()!.containsKey('role')) { role = snapshot.get("role").toString(); print('获取到角色: $role'); } else { print('文档无role字段,使用默认值'); } } else { print('文档不存在于数据库'); } } catch (e) { print('获取角色出错: $e'); } return role; } class FireStoreConstants { static const String users = 'users'; }
3. 优化MainPage的角色判断逻辑
在MainPage中使用全局getRole,并添加兜底处理:
@override Widget build(BuildContext context) { return Scaffold( body: StreamBuilder<User?>( stream: FirebaseAuth.instance.authStateChanges(), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { return const Center(child: Text('Something Went Wrong!')); } else if (snapshot.hasData) { final user = snapshot.data!; return FutureBuilder<String>( future: getRole(user.uid), builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { return const Center(child: CircularProgressIndicator()); } else if (snapshot.hasError) { print('获取角色错误: ${snapshot.error}'); return const Center(child: Text('获取用户角色失败!')); } else { final String role = snapshot.data ?? 'member'; print('当前用户角色: $role'); if (role == "admin") { return const AdminPage(); } else if (role == "staff") { return const StaffPage(); } else if (role == "member") { return const MemberPage(); } else if (role == "collector") { return const CollectorPage(); } else { print('未知角色: $role'); return const SigninPage(); } } }, ); } else { return const SigninPage(); } }, ), ); }
4. 配置Firestore安全规则
确保已认证用户可读取自己的文档:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /users/{userId} { allow read, write: if request.auth != null && request.auth.uid == userId; } } }
验证步骤
- 卸载旧应用,重新安装后注册新用户。
- 登录Firestore控制台,确认
users集合中存在以用户UID为ID的文档,且包含role字段。 - 登录应用,查看控制台日志,确认角色值正确并跳转至对应页面。
内容的提问来源于stack exchange,提问作者Ami Jasper A
相关产品推荐
相关产品推荐

