簡體   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