You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Flutter基于角色的认证异常:始终停留在SigninPage无法跳转

问题:Flutter Firebase认证后无法根据角色跳转对应页面

开发Flutter毕设应用时,为Admin、Staff、Member、Collector四类用户分配了对应页面,但用户完成认证后始终停留在SigninPage,无法跳转至对应角色页面。


核心问题排查

从代码中可定位两个关键问题:

  1. 注册时Firestore文档ID与Auth UID不匹配:注册使用add()方法生成随机文档ID,而getRole通过Auth的UID查询文档,导致查询不到对应数据。
  2. 注册未写入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;
    }
  }
}

验证步骤

  1. 卸载旧应用,重新安装后注册新用户。
  2. 登录Firestore控制台,确认users集合中存在以用户UID为ID的文档,且包含role字段。
  3. 登录应用,查看控制台日志,确认角色值正确并跳转至对应页面。

内容的提问来源于stack exchange,提问作者Ami Jasper A

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 22:14:55