繁体   English   中英

Flutter:在 Firebase 中有不同的身份验证提供程序

[英]Flutter: have different authentication providers in Firebase

我的应用程序中有不同的登录方法:

  • Facebook
  • 谷歌
  • 苹果
  • 电子邮件

对于这个问题,我将重点关注前两个问题。 当用户使用 Facebook 登录时,提供程序如下所示:

在此处输入图像描述

没关系,但如果我注销并再次登录,这次使用新的 Google 帐户但使用相同的电子邮件,提供商看起来像这样:

在此处输入图像描述

现在,如果我注销并再次使用 Facebook 登录,我将面临account-exists-with-different-credential错误。 我已经准备好逻辑并显示其提供者登录方法的东西,但是这个用户应该有两个提供者可用,并且他应该能够使用这两种方法登录。

这是我的代码:

Future facebookSignIn(BuildContext context) async {
    final LoginResult result = await FacebookAuth.instance.login();

    if (result.status == LoginStatus.success) {
      final AccessToken accessToken = result.accessToken!;
      AuthCredential credential =
          FacebookAuthProvider.credential(accessToken.token);
      await _firebaseCredential(context, credential);
    }
  }

 Future googleSignIn(BuildContext context,
      [String? email, facebookCredential]) async {
    try {
      GoogleSignInAccount googleUser;
      dynamic popup = await _googleSignIn.signIn();

      // cancelled login
      if (popup == null) {
        return null;
      }

      googleUser = popup;

      GoogleSignInAuthentication googleAuth = await googleUser.authentication;
      final AuthCredential credential = GoogleAuthProvider.credential(
        accessToken: googleAuth.accessToken,
        idToken: googleAuth.idToken,
      );
      await _firebaseCredential(context, credential);
    } on FirebaseAuthException catch (e) {
      // await FirebaseCrashlytics.instance.recordError(
      //   e,
      //   StackTrace.fromString("/googleSignIn"),
      //   reason: e.message,
      // );
      // return null;
    }
  }

 _firebaseCredential(BuildContext context, credential) async {
    try {
      User user =
          (await FirebaseAuth.instance.signInWithCredential(credential)).user!;
      // Provider.of<MyRents>(context, listen: false).updateUI();
      await firebaseProfile.updateUserData(context, user);
    } on FirebaseAuthException catch (error) {
      // final error = e as FirebaseAuthException;
      if (error.code == 'account-exists-with-different-credential') {
        String email = error.email!;
        // AuthCredential pendingCredential = e.credential;

        List<String> signInMethods =
            await FirebaseAuth.instance.fetchSignInMethodsForEmail(email);

        // If the user has several sign-in methods,
        // the first method in the list will be the "recommended" method to use.
        if (signInMethods.first == 'google.com' ||
            signInMethods.first == 'facebook.com') {
          // TODO: fix facebook
          return await googleSignIn(context, email, credential);
        } else {
          ScaffoldMessenger.of(context)
              .showSnackBar(SnackBar(content: Text(error.message!)));
        }
      } else {
        ScaffoldMessenger.of(context)
            .showSnackBar(SnackBar(content: Text(error.message!)));
      }
    }
  }

我错过了什么吗?

flutter_facebook_auth: ^4.3.3
google_sign_in: ^5.2.1
Future googleSignIn(BuildContext context,
      [String? email, facebookCredential]) async {
    try {
      GoogleSignInAccount googleUser;
      dynamic popup = await _googleSignIn.signIn();

      // cancelled login
      if (popup == null) {
        return null;
      }

      googleUser = popup;

      GoogleSignInAuthentication googleAuth = await googleUser.authentication;
      final AuthCredential credential = GoogleAuthProvider.credential(
        accessToken: googleAuth.accessToken,
        idToken: googleAuth.idToken,
      );
      await _firebaseCredential(context, credential);
    } on FirebaseAuthException catch (e) {
      // await FirebaseCrashlytics.instance.recordError(
      //   e,
      //   StackTrace.fromString("/googleSignIn"),
      //   reason: e.message,
      // );
      // return null;
    }
  }

Future facebookSignIn(BuildContext context) async {
    final LoginResult result = await FacebookAuth.instance.login();

    if (result.status == LoginStatus.success) {
      final AccessToken accessToken = result.accessToken!;
      AuthCredential credential =
          FacebookAuthProvider.credential(accessToken.token);

      await _firebaseCredential(context, credential);
    }
  }

// other methods...

_firebaseCredential(BuildContext context, credential) async {
    try {
      User user =
          (await FirebaseAuth.instance.signInWithCredential(credential)).user!;
      await firebaseProfile.updateUserData(context, user);
    } on FirebaseAuthException catch (error) {
      if (error.code == 'account-exists-with-different-credential') {
        String email = error.email!;
        List<String> signInMethods =
            await FirebaseAuth.instance.fetchSignInMethodsForEmail(email);
        // bool newUser = (signInMethods.length > 0) ? false : true;

        // If the user has several sign-in methods,
        // the first method in the list will be the "recommended" method to use.
        var user;
        switch (signInMethods.first) {
          case 'google.com':
            user = await googleSignIn(context, email, credential);
            break;
          case 'facebook.com':
            user = await facebookSignIn(context);
            break;
          case 'apple.com':
            user = await appleSignIn(context);
            break;
          case 'password':
            // since password is managed by user we force have email provider only
            ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                content: Text(translate('auth.signInMethods_password'))));
            break;
          // TODO: apple
        }
        await linkProvider(context, credential);
        return user;
      }

      return ScaffoldMessenger.of(context)
          .showSnackBar(SnackBar(content: Text(error.message!)));
    }
  }

  // just some extra error covering
  Future linkProvider(BuildContext context, credential) async {
    try {
      await FirebaseAuth.instance.currentUser?.linkWithCredential(credential);
    } on FirebaseAuthException catch (e) {
      switch (e.code) {
        case "provider-already-linked":
          ScaffoldMessenger.of(context).showSnackBar(SnackBar(
              content: Text(translate('auth.provider_already_linked'))));
          break;
        case "invalid-credential":
          ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text(translate('auth.invalid_credential'))));
          break;
        case "credential-already-in-use":
          ScaffoldMessenger.of(context).showSnackBar(SnackBar(
              content: Text(translate('auth.credential_already_in_use'))));
          break;
        default:
          ScaffoldMessenger.of(context).showSnackBar(
              SnackBar(content: Text(translate('auth.something_happened'))));
      }
    }
  }

如果您使用 Google -> Facebook,它将如下所示:

在此处输入图像描述

如果您的 Google 电子邮件是受信任的电子邮件 (gmail),则只有 Google 才会出现。 更多信息: https ://groups.google.com/g/firebase-talk/c/ms_NVQem_Cw/m/8g7BFk1IAAAJ

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM