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

如何在Flutter中关联Firebase Auth用户ID与Firestore用户ID

用户注册与Firestore档案关联实现方案

核心逻辑

必须先通过Firebase Auth完成用户账号创建,拿到系统生成的唯一UID,再用这个UID作为Firestore文档ID,将用户名、邮箱等档案信息写入users集合,这样就能保证Auth账号和Firestore档案一一对应。

原代码存在的问题

  1. 执行顺序颠倒:先写Firestore再创建Auth用户,导致无法获取真实用户UID,还错误用了固定字符串"uid"作为文档ID,根本关联不到真实用户。
  2. 数据存储错误:直接把TextEditingController对象存进Firestore,而不是用户输入的文本内容(应该取.text属性)。
  3. 错误处理脱节:Firestore写入和Auth创建没有绑定,Auth创建失败时,Firestore可能已经写入无效数据。

修正后的完整代码

import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/material.dart';
import 'package:flutter_dev/reusable.dart';
import 'package:flutter_dev/home.dart';

class SignUp extends StatefulWidget {
  const SignUp({super.key});

  @override
  State<SignUp> createState() => _SignUpState();
}

class _SignUpState extends State<SignUp> {
  final TextEditingController _passwordTextController = TextEditingController();
  final TextEditingController _emailTextController = TextEditingController();
  final TextEditingController _userNameTextController = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      resizeToAvoidBottomInset: false,
      extendBodyBehindAppBar: true,
      appBar: AppBar(
        backgroundColor: Colors.transparent,
        elevation: 0,
        title: const Text('Sign Up'),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            const SizedBox(height: 20),
            reusableTextField(
              "Enter Username",
              Icons.person_outline,
              false,
              _userNameTextController,
              context,
            ),
            const SizedBox(height: 20),
            reusableTextField(
              "Enter Email ID",
              Icons.email_outlined,
              false,
              _emailTextController,
              context,
            ),
            const SizedBox(height: 20),
            reusableTextField(
              "Enter Password",
              Icons.lock_outline,
              true,
              _passwordTextController,
              context,
            ),
            const SizedBox(height: 20),
            signInsignUpButton(context, false, () async {
              try {
                // 第一步:创建Firebase Auth用户,获取唯一UID
                UserCredential userCredential = await FirebaseAuth.instance
                    .createUserWithEmailAndPassword(
                  email: _emailTextController.text.trim(),
                  password: _passwordTextController.text.trim(),
                );

                String userId = userCredential.user!.uid;
                final db = FirebaseFirestore.instance;

                // 第二步:用UID作为文档ID,写入用户档案到Firestore
                await db.collection("users").doc(userId).set({
                  'userName': _userNameTextController.text.trim(),
                  'email': _emailTextController.text.trim(),
                  'accountCreated': Timestamp.now(),
                  'avatarUrl': 'https://example.com/default-avatar.png', // 默认头像,后续可让用户修改
                });

                print("账号与档案创建成功");
                // 跳转到首页,先检查Widget是否还挂载
                if (!mounted) return;
                Navigator.pushReplacement(
                  context,
                  MaterialPageRoute(builder: (context) => const Home()),
                );
              } on FirebaseAuthException catch (e) {
                print("Auth错误: ${e.message}");
                if (!mounted) return;
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text(e.message ?? "注册失败")),
                );
              } on FirebaseException catch (e) {
                print("Firestore错误: ${e.message}");
                if (!mounted) return;
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text("档案创建失败: ${e.message}")),
                );
              } catch (e) {
                print("未知错误: $e");
                if (!mounted) return;
                ScaffoldMessenger.of(context).showSnackBar(
                  const SnackBar(content: Text("注册出错了")),
                );
              }
            }),
          ],
        ),
      ),
    );
  }
}

关键细节说明

  • Firestore结构:自动创建users集合,每个文档的ID就是Auth生成的UID,文档内包含用户名、邮箱、创建时间、默认头像URL等字段。
  • 输入处理:用.trim()去除输入文本前后的空格,避免存储无效的空白内容。
  • 异步优化:用async/await替代链式then,代码逻辑更清晰,错误处理更集中。
  • Widget安全:添加mounted检查,防止Widget销毁后执行导航、弹窗等操作引发错误。
  • 后续扩展:如果要支持用户上传头像,可以用Firebase Storage存储图片文件,然后把图片的下载URL更新到Firestore的avatarUrl字段即可。

内容的提问来源于stack exchange,提问作者Boatti

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 02:40:34