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

Flutter:使用Apple/Google登录时从Firebase Authentication获取用户UID

问题描述

最近给应用添加了「Sign in with Apple」和「Sign In with Google」功能,此前用户通过邮箱密码注册时,会以Firebase的用户UID作为文档名创建用户文档。现在需要获取Firebase用户数据表中的标准UID(如图),替换当前Apple登录中使用的oauthCredential.idToken、appleCredential.userIdentifier,以及Google登录中使用的gUser.id,统一用Firebase UID作为文档名和用户数据中的uid字段。

Firebase用户UID截图

当前Apple登录代码

signInWithApple() async {
    final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;

    final rawNonce = generateNonce();
    final nonce = sha256ofString(rawNonce);

    try {
      final appleCredential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
        nonce: nonce
      );

      final oauthCredential = OAuthProvider("apple.com").credential(
        idToken: appleCredential.identityToken,
        rawNonce: rawNonce,
      );

      //*Create User Doc
      final doc = FirebaseFirestore.instance
          .collection("users")
          .doc(oauthCredential.idToken);

      final parkbestUser = ParkbestUser(
        email: appleCredential.email.toString(),
        uid: appleCredential.userIdentifier.toString(),
        creationTime: DateTime.now().millisecondsSinceEpoch,
        isController: false,
        controllCity: "",
        signInMethod: "apple.com",
      );

      final json = parkbestUser.toJson();

      try {
        await doc.set(json);
        await _firebaseAuth.signInWithCredential(oauthCredential);
      } catch (e) {
        print(e.toString());
      }

      final authResult =
          await _firebaseAuth.signInWithCredential(oauthCredential);

      final displayName =
          '${appleCredential.givenName} ${appleCredential.familyName}';
      final userEmail = '${appleCredential.email}';

      final firebaseUser = authResult.user;
      print(displayName);
      await firebaseUser!.updatePhotoURL("");
      await firebaseUser.updateDisplayName(displayName);
      await firebaseUser.updateEmail(userEmail);

      return firebaseUser;
    } catch (exception) {
      print(exception);
    }
    return null;
  }

当前Google登录代码

signInWithGoogle() async {
    final GoogleSignInAccount? gUser = await GoogleSignIn().signIn();

    final GoogleSignInAuthentication gAuth = await gUser!.authentication;

    final credential = GoogleAuthProvider.credential(
      accessToken: gAuth.accessToken,
      idToken: gAuth.idToken,
    );

    //*Create User Doc
    final userDoc =
        FirebaseFirestore.instance.collection("users").doc(gUser.id);

    final parkbestUser = ParkbestUser(
      email: gUser.email,
      uid: gUser.id,
      creationTime: DateTime.now().millisecondsSinceEpoch,
      isController: false,
      controllCity: "",
      signInMethod: credential.signInMethod,
    );

    final json = parkbestUser.toJson();

    try {
      await userDoc.get().then((doc) {
        if (!doc.exists) {
          userDoc.set(json);
        } else {}
      });
      return await FirebaseAuth.instance.signInWithCredential(credential);
    } catch (e) {
      print("------------------- - - - - - - - - - $e");
    }
  }

核心问题

如何获取Firebase的标准UID,并将其用于创建每个用户的文档?


解决方案

Firebase的标准用户UID是在成功完成Firebase认证后,从返回的User对象中获取的。必须先调用signInWithCredential完成Firebase登录,再用user.uid拿到目标UID,而不是提前使用第三方登录的标识。

修改Apple登录代码

调整逻辑顺序,先完成Firebase认证,再创建用户文档:

signInWithApple() async {
    final FirebaseAuth _firebaseAuth = FirebaseAuth.instance;

    final rawNonce = generateNonce();
    final nonce = sha256ofString(rawNonce);

    try {
      final appleCredential = await SignInWithApple.getAppleIDCredential(
        scopes: [
          AppleIDAuthorizationScopes.email,
          AppleIDAuthorizationScopes.fullName,
        ],
        nonce: nonce
      );

      final oauthCredential = OAuthProvider("apple.com").credential(
        idToken: appleCredential.identityToken,
        rawNonce: rawNonce,
      );

      // 1. 先完成Firebase登录,获取用户对象
      final authResult = await _firebaseAuth.signInWithCredential(oauthCredential);
      final firebaseUser = authResult.user;
      if (firebaseUser == null) return null;

      // 2. 获取Firebase标准UID
      final firebaseUid = firebaseUser.uid;

      // 3. 更新用户信息(如昵称、邮箱)
      final displayName = '${appleCredential.givenName} ${appleCredential.familyName}';
      final userEmail = appleCredential.email;
      await firebaseUser.updatePhotoURL("");
      if (displayName.isNotEmpty) await firebaseUser.updateDisplayName(displayName);
      if (userEmail != null) await firebaseUser.updateEmail(userEmail);

      // 4. 用Firebase UID创建/更新用户文档
      final doc = FirebaseFirestore.instance.collection("users").doc(firebaseUid);
      final parkbestUser = ParkbestUser(
        email: userEmail ?? "",
        uid: firebaseUid, // 替换为Firebase UID
        creationTime: DateTime.now().millisecondsSinceEpoch,
        isController: false,
        controllCity: "",
        signInMethod: "apple.com",
      );
      final json = parkbestUser.toJson();

      // 检查文档是否存在,不存在则创建
      final docSnapshot = await doc.get();
      if (!docSnapshot.exists) {
        await doc.set(json);
      }

      return firebaseUser;
    } catch (exception) {
      print(exception);
    }
    return null;
  }

修改Google登录代码

同样先完成Firebase认证,再获取UID创建文档:

signInWithGoogle() async {
    try {
      final GoogleSignInAccount? gUser = await GoogleSignIn().signIn();
      if (gUser == null) return null;

      final GoogleSignInAuthentication gAuth = await gUser.authentication;
      final credential = GoogleAuthProvider.credential(
        accessToken: gAuth.accessToken,
        idToken: gAuth.idToken,
      );

      // 1. 先完成Firebase登录,获取用户对象
      final authResult = await FirebaseAuth.instance.signInWithCredential(credential);
      final firebaseUser = authResult.user;
      if (firebaseUser == null) return null;

      // 2. 获取Firebase标准UID
      final firebaseUid = firebaseUser.uid;

      // 3. 用Firebase UID创建/更新用户文档
      final userDoc = FirebaseFirestore.instance.collection("users").doc(firebaseUid);
      final parkbestUser = ParkbestUser(
        email: gUser.email,
        uid: firebaseUid, // 替换为Firebase UID
        creationTime: DateTime.now().millisecondsSinceEpoch,
        isController: false,
        controllCity: "",
        signInMethod: credential.signInMethod,
      );
      final json = parkbestUser.toJson();

      // 检查文档是否存在,不存在则创建
      final docSnapshot = await userDoc.get();
      if (!docSnapshot.exists) {
        await userDoc.set(json);
      }

      return firebaseUser;
    } catch (e) {
      print("------------------- - - - - - - - - - $e");
    }
    return null;
  }

关键修改点

  • 将signInWithCredential移到创建文档之前,确保先拿到Firebase用户对象
  • 使用firebaseUser.uid作为文档ID和ParkbestUser的uid字段值
  • 统一文档存在性检查逻辑,避免重复创建
  • 调整Apple登录中的用户信息更新顺序,确保先登录再修改信息

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 16:52:54