【问题标题】:Handling linking accounts in Firebase在 Firebase 中处理关联帐号
【发布时间】:2016-09-12 22:09:23
【问题描述】:

我正在遵循 Firebase 关于社交登录的说明。下面是我正在使用的示例,从登录身份验证的角度来看,它一切正常。

但是,我的 Google 和 Facebook 登录都独立工作。

我现在想做的是链接帐户。实际上,您可以在下面看到这可能会发生什么(查看评论):

如果您在应用上使用多个身份验证提供程序,您应该在此处处理链接用户帐户。

我尝试了许多我认为应该放在这里的变体,但无济于事。任何人都可以指导我他们认为应该去哪里吗?谢谢!

function initFBApp() {
    // Result from Redirect auth flow.
    // [START getidptoken]
    firebase.auth().getRedirectResult().then(function (result) {
        if (result.credential) {
            // This gives you a Facebook Access Token. You can use it to access the Facebook API.
            var token = result.credential.accessToken;
            // [START_EXCLUDE]
            document.getElementById('FBquickstart-oauthtoken').textContent = token;
        }
        else {
            document.getElementById('FBquickstart-oauthtoken').textContent = 'null';
            // [END_EXCLUDE]
        }
        // The signed-in user info.
        var user = result.user;
    }).catch(function (error) {
        // Handle Errors here.
        var errorCode = error.code;
        var errorMessage = error.message;
        // The email of the user's account used.
        var email = error.email;
        // The firebase.auth.AuthCredential type that was used.
        var credential = error.credential;
        // [START_EXCLUDE]
        if (errorCode === 'auth/account-exists-with-different-credential') {
            alert('You have already signed up with a different auth provider for that emails.');
            // If you are using multiple auth providers on your app you should handle linking
            // the user's accounts here.
        }
        else {
            console.error(error);
        }
        // [END_EXCLUDE]
    });
    // [END getidptoken]
    // Listening for auth state changes.
    // [START authstatelistener]
    firebase.auth().onAuthStateChanged(function (user) {
        if (user) {
            // User is signed in.
            var displayName = user.displayName;
            var email = user.email;
            var emailVerified = user.emailVerified;
            var photoURL = user.photoURL;
            var isAnonymous = user.isAnonymous;
            var uid = user.uid;
            var providerData = user.providerData;
            // [START_EXCLUDE]
            document.getElementById('FBquickstart-sign-in-status').textContent = 'Signed in';
            document.getElementById('FBquickstart-sign-in').textContent = 'Log out';
            document.getElementById('FBquickstart-account-details').textContent = JSON.stringify(user, null, '  ');
            // [END_EXCLUDE]
        }
        else {
            // User is signed out.
            // [START_EXCLUDE]
            document.getElementById('FBquickstart-sign-in-status').textContent = 'Signed out';
            document.getElementById('FBquickstart-sign-in').textContent = 'Log in with Facebook';
            document.getElementById('FBquickstart-account-details').textContent = 'null';
            document.getElementById('FBquickstart-oauthtoken').textContent = 'null';
            // [END_EXCLUDE]
        }
        // [START_EXCLUDE]
        document.getElementById('FBquickstart-sign-in').disabled = false;
        // [END_EXCLUDE]
    });
    // [END authstatelistener]
    document.getElementById('FBquickstart-sign-in').addEventListener('click', toggleFBSignIn, false);
}

【问题讨论】:

  • 您是否在没有 Firebase 身份验证后端要求的情况下手动链接帐户?还是您这样做是因为您收到错误“auth/account-exists-with-different-credential”?
  • 我想链接它们,以便用户拥有一个帐户而不是多个帐户。通过第二种机制进行身份验证时,我成功收到了上述错误。我现在想用帐户链接替换“auth/account-exists-with-different-credential”消息
  • 不确定我是否理解,但如果您在登录时遇到该错误,并因此尝试链接返回该错误的帐户。在下面检查我的答案。

标签: javascript firebase facebook-login firebase-authentication social


【解决方案1】:

这些是关于如何处理身份验证/帐户存在与不同凭据的大致步骤: 如果您正在登录使用另一个已存在帐户的电子邮件的新 Facebook 帐户,您将收到该错误。假设现有帐户是一个 google 帐户。

您将在getRedirectResult().catch(function(error) {}) 中收到该错误

该错误还将包含电子邮件和凭据字段。 您将需要保存凭证(使用推荐的 sessionStorage)。查看这篇文章以了解更多信息: Firebase Authentication Javascript: setCookie for pending Credential for redirect

然后您致电firebase.auth().fetchProvidersForEmail(error.email) 以确定该电子邮件已存在的提供商。

然后,您将登录这些现有提供商之一,并声明该电子邮件与 error.email 相同。成功后,您将从 sessionStorage 加载待处理的凭据,按照另一篇文章中的说明重新初始化并将其链接到 currentUser:

firebase.auth().currentUser.linkWithCredential(savedCred);

您现在将链接两个帐户。请记住,现有提供程序可能是密码类型。在这种情况下,您不需要保存凭据,只需向用户询问密码并使用相同的电子邮件 error.email 登录。然后您可以直接使用 error.credential 调用链接。

顺便说一句,我推荐 firebaseui-web 为您处理所有这些: https://github.com/firebase/firebaseui-web

【讨论】:

  • 我很好奇为什么建议在用户的电子邮件地址下已经存在密码类型的帐户时询问用户的密码。当用户使用相同的电子邮件地址通过社交服务提供商进行身份验证时,这还不足以证明他们是该电子邮件地址的所有者吗?从可用性的角度来看,让用户静默登录到他们现有的帐户会更友好。
  • 同意易用性这一点,但 firebase Auth 在安全性方面是保守的/额外安全的。谷歌将安全漏洞称为“露营”,即一个人使用另一个提供商(如 Facebook)来隐藏电子邮件。某些服务不验证电子邮件,或者不验证 100%,例如更改电子邮件。因此,如果他们在 Facebook 上更改了电子邮件,就有可能获得对您应用程序帐户的访问权限。这是一个边缘情况,但安全性对边缘情况是偏执的。
【解决方案2】:

我认为 Firebase API changed a bitfirebase.auth().currentUser.link(savedCred); 现在是firebase.auth().currentUser.linkWithRedirect(provider)。在我的实现中,我将最初选择的提供程序保存到 sessionStorage 并与上述方法一起使用,以防需要帐户链接。

如果更适合您的需求,您也可以使用linkWithPopUp

【讨论】:

  • 如何理解是否需要链接?我的意思是什么时候发送链接请求。
  • 我认为这是现在更好的答案,而且肯定比文档告诉你的更好,因为它们都与凭据等合并。谢谢 Ashton。
  • 我在互联网上看到的大多数答案都需要以前登录的用户,但是在注册该电子邮件已使用其他提供商注册的情况下,我们将如何做到这一点。我们可以参考 codepen 的行为,其中我最初使用 github 提供程序注册,然后使用 twitter 提供程序注销并登录 - 最后,它仍然是一个帐户。
【解决方案3】:

下面是工作代码的相关 sn-p(它位于异步函数中)。请注意,“apples”只是 Firestore 中代表购物车的简化测试记录。

if(error.code === "auth/email-already-in-use"){
    // REMEMBER AUTH CURRENT USER OBJECT
    previousUser = firebase.auth().currentUser;
    // WE MUST HANDLE DB READ AND DELETE WHILE SIGNED IN AS PREVIOUS USER PER FIRESTORE SECURITY RULES
    if(localUserDoc){ //this was saved from .snapshot firing
        if(localUserDoc.data().apples){
            apples = localUserDoc.data().apples;
        }                    
    }
    //DELETE CURRENT USER RECORD WHILE STILL SIGNED IN
    await firebase.firestore().collection("users").doc(previousUser.uid).delete();
    // CLEAN UP DONE. NOW SIGN IN USING EMAIL LINK CREDENTIAL
    try {
        var firebaseUserObj = await firebase.auth().signInAndRetrieveDataWithCredential(credential);
        // FIRESTORE USER RECORD FOR EMAIL LINK USER WAS CREATED WHEN THEY ADDED APPLE TO CART
        try {
            var doc = await firebase.firestore().collection("users").doc(firebaseUserObj.user.uid).get();
            if (doc.exists) {
                if(doc.data().apples){
                    apples = apples + doc.data().apples;
                }
            }
            await firebase.firestore().collection("users").doc(firebaseUserObj.user.uid).update({
                apples: apples
            });
        } catch(error) {
            console.log("Error getting document:", error);
        }
        previousUser.delete();
    } catch (error) {
        console.log(".signInWithCredential err ", error);
    }
}

【讨论】:

    【解决方案4】:

    仔细阅读示例https://firebase.google.com/docs/auth/web/google-signin “处理不同凭据错误的帐户存在”部分

    重定向模式 这个错误在重定向中的处理方式类似 模式,不同之处在于必须缓存待处理的凭据 在页面重定向之间(例如,使用会话存储)。

    【讨论】:

      猜你喜欢
      • 2017-09-05
      • 1970-01-01
      • 1970-01-01
      • 2018-05-10
      • 1970-01-01
      • 2017-08-31
      • 2013-05-14
      • 2021-06-26
      • 1970-01-01
      相关资源
      最近更新 更多