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字段。

当前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
相关产品推荐
相关产品推荐

