Firebase Google登录:如何判断用户是否已存在并自动跳转首页
问题
我想在用户通过Google登录时检查该用户是否已存在于Firebase中。我的应用里用户注册时会调用signInWithGoogle方法,代码如下:
Future<User?> signInWithGoogle() async { await Firebase.initializeApp(); User? user; if (kIsWeb) { GoogleAuthProvider authProvider = GoogleAuthProvider(); try { final UserCredential userCredential = await _auth.signInWithPopup(authProvider); user = userCredential.user; } catch (e) { print(e); } } else { try { final GoogleSignIn googleSignIn = GoogleSignIn(); final GoogleSignInAccount? googleSignInAccount = await googleSignIn.signIn().catchError((onError) => print(onError)); ; if (googleSignInAccount != null) { final GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount.authentication; final AuthCredential credential = GoogleAuthProvider.credential( accessToken: googleSignInAuthentication.accessToken, idToken: googleSignInAuthentication.idToken, ); try { final UserCredential userCredential = await _auth.signInWithCredential(credential); user = userCredential.user; } on FirebaseAuthException catch (e) { if (e.code == 'account-exists-with-different-credential') { print('The account already exists with a different credential.'); } else if (e.code == 'invalid-credential') { print('Error occurred while accessing credentials. Try again.'); } } catch (e) { print(e); } } } catch (e) { print(e); } } if (user != null) { uid = user.uid; name = user.displayName; userEmail = user.email; imageUrl = user.photoURL; SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setBool('auth', true); prefs.setString('id', user.uid); prefs.setString('name', user.displayName!); } return user; }
但这个方法无法区分用户是新注册还是已存在的老用户,我需要在Google登录后判断:如果是老用户则自动跳转首页,新用户则继续完成注册流程。请问该如何实现?
解决方案
核心是利用Firebase返回的UserCredential对象中的additionalUserInfo.isNewUser属性,这个属性会直接告诉你当前登录的用户是否是首次创建账号。
修改后的代码(支持区分新/老用户)
我们可以修改方法的返回值,同时返回用户对象和是否为新用户的状态:
// 使用Dart 3.0+的记录类型返回结果 Future<({User? user, bool isNewUser})> signInWithGoogle() async { await Firebase.initializeApp(); User? user; bool isNewUser = false; if (kIsWeb) { GoogleAuthProvider authProvider = GoogleAuthProvider(); try { final UserCredential userCredential = await _auth.signInWithPopup(authProvider); user = userCredential.user; // 标记是否为新用户 isNewUser = userCredential.additionalUserInfo?.isNewUser ?? false; } catch (e) { print(e); } } else { try { final GoogleSignIn googleSignIn = GoogleSignIn(); final GoogleSignInAccount? googleSignInAccount = await googleSignIn.signIn().catchError((onError) => print(onError)); if (googleSignInAccount != null) { final GoogleSignInAuthentication googleSignInAuthentication = await googleSignInAccount.authentication; final AuthCredential credential = GoogleAuthProvider.credential( accessToken: googleSignInAuthentication.accessToken, idToken: googleSignInAuthentication.idToken, ); try { final UserCredential userCredential = await _auth.signInWithCredential(credential); user = userCredential.user; // 标记是否为新用户 isNewUser = userCredential.additionalUserInfo?.isNewUser ?? false; } on FirebaseAuthException catch (e) { if (e.code == 'account-exists-with-different-credential') { print('该账号已通过其他方式注册。'); } else if (e.code == 'invalid-credential') { print('获取凭证出错,请重试。'); } } catch (e) { print(e); } } } catch (e) { print(e); } } if (user != null) { uid = user.uid; name = user.displayName; userEmail = user.email; imageUrl = user.photoURL; SharedPreferences prefs = await SharedPreferences.getInstance(); prefs.setBool('auth', true); prefs.setString('id', user.uid); prefs.setString('name', user.displayName!); } return (user: user, isNewUser: isNewUser); }
调用方法并处理跳转
在调用signInWithGoogle的地方,根据返回的isNewUser状态处理逻辑:
void handleGoogleSignIn() async { final result = await signInWithGoogle(); if (result.user != null) { if (result.isNewUser) { // 新用户:继续完成注册流程 Navigator.pushNamed(context, '/complete-registration'); } else { // 老用户:直接跳转首页 Navigator.pushReplacementNamed(context, '/home'); } } }
注意事项
additionalUserInfo?.isNewUser可能为null,所以用?? false兜底,确保逻辑不会出错。- 如果用户之前通过其他方式(如邮箱密码)注册过同一邮箱,Firebase会抛出
account-exists-with-different-credential错误,你可以在catch块中处理这种场景,比如提示用户改用原登录方式。
内容的提问来源于stack exchange,提问作者Cidiko Andorem
相关产品推荐
相关产品推荐

