代码之家  ›  专栏  ›  技术社区  ›  Laker

Firestore+AngularFire-链接帐户

  •  2
  • Laker  · 技术社区  · 6 年前

    我想为用户提供多个登录选项。目前,谷歌和Facebook。 但当用户登录Google并稍后尝试登录Facebook时,我会遇到一个错误:

    已存在具有相同电子邮件地址但不同的帐户 登录凭据。使用与此关联的提供程序登录 电子邮件地址。

    所以我必须把账户联系起来。我没有找到任何相关文档,除了 this 这没什么帮助。我能找到的最好的信息是 stackoverflow 但出于某种原因,这对我来说还不够。 解决方案涉及 signInWithPopup 这给了我一个错误:

    “无法与弹出窗口建立连接。可能是 被浏览器阻止。“” 因此,如果弹出窗口不起作用,我将调用signInWithRedirect:

    private authLoginWithPopup(provider: AuthProvider) {
      this.afAuth.auth.signInWithPopup(provider)
        .then((result) => {
          this.credential = result.credential;
          this.updateUserData(result);
        })
        .catch(error => {
          if (error.code === 'auth/account-exists-with-different-credential') {
            this.mergeCredentials(error);
          } else if (error.code === 'auth/popup-blocked') {
            this.authLoginWithRedirect(new firebase.auth.GoogleAuthProvider());
          }
        });
    }
    

    弹出后,您将进入 then 可以做任何事。但重定向后,您会丢失信息。所以我把它储存在 localStorage :

    this.afAuth.auth.fetchProvidersForEmail(error.email).then(providers => {
      const [ provider ] = providers;
      if (provider === 'google.com') {
        const googleProvider = new firebase.auth.GoogleAuthProvider();
        googleProvider.setCustomParameters({ login_hint: error.email });
        localStorage.setItem('auth_error', JSON.stringify(error.credential));
        this.authLoginWithPopup(googleProvider);
      }
    });
    

    我在getRedirectResult中检索它:

    constructor(
      private afAuth: AngularFireAuth,
      private afs: AngularFirestore,
    ) {
      this.afAuth.auth.getRedirectResult().then(result => {
        if (result.user) {
          this.credential = result.credential;
          const authError = JSON.parse(localStorage.getItem('auth_error'));
    
          if (authError) {
            localStorage.removeItem('auth_error');
    
            this.afAuth.auth.signInWithCredential(
              firebase.auth.GoogleAuthProvider.credential(
                null, (<any>this.credential).accessToken
              )
            )
              .then(user => {
                user.linkWithCredential(authError)
              })
              .catch(error => {
                console.log('error', error);
              });
          }
        }
      });
    }
    

    (这会产生另一个问题。我如何知道这是一个直接登录Google的用户的正常登录重定向。还是一个在用户尝试登录Facebook并由于此错误被提示登录Google后的重定向?我不想每次都合并凭据。但这是一个较小的问题。但我也希望找到解决此问题的方法。)

    但是 signInWithCredential 给我这个错误:

    linkWithCredential失败:第一个参数“credential”必须是有效的 资质

    我找到了“解决方案” here :

    呼叫时 使用凭据登录 使用需要调用的访问令牌 它是这样的:

    signInWithCredential(null, token); 如果你正在做 signInWithCredential(token) 那么您需要使用ID标记,而不是 而不是访问令牌。

    我尝试了两种版本,都没有成功 .第二版: this.afAuth.auth.signInWithCredential(firebase.auth.GoogleAuthProvider.credential((<any>this.credential).idToken)) 类型转换之所以存在,是因为我想类型定义中存在问题。

    我试着插入整个 credentials 对象 idToken 作为第一个参数, accessToken 作为第二个参数。但我总是得到: 第一个参数“credential”必须是有效的凭据。

    在我写这篇文章的时候,我突然想到这可能是 linkWithCredential 而不是 使用凭据登录 方法根据错误消息,这应该是显而易见的。我只是没有注意到,因为谷歌搜索错误给了我这个解决方案。所以我很快检查了 authError 变量有 accessToken ,则, providerId signInMethod 方法没有 tokenId .所以我试着 accessToken 作为一个参数,而不是整个对象,它没有帮助。我试着把它作为 null, accessToken .没有帮助。我试图找到的文档 linkWithCredential链接 方法,没有任何运气。所以我不知道它在期待什么。

    我已经在这上面浪费了四天了。这让我失去了很多精神健康。谁能帮帮我吗?

    1 回复  |  直到 6 年前
        1
  •  1
  •   bojeil    6 年前

    您可以存储基础OAuth凭据(id令牌或访问令牌): error.credential.idToken error.credential.accessToken 及其提供商ID, error.credential.providerId 。返回页面后,您可以重新初始化凭据,类似于: firebase.auth.FacebookAuthProvider.credential(accessToken) .成功重定向Google登录后,链接该凭据