在 AngularFire2 中关联账户

Linking accounts in AngularFire2

我正在使用 AngularFire2 处理匿名帐户和 Google 帐户。如果用户使用 Google 帐户登录,我想将他们的匿名帐户转换为他们的永久 (Google) 帐户,这样他们就可以继续无缝地使用该应用程序。

使用 Firebase API 似乎很容易,但我在 AngularFire2 中看不到这样做的能力。

对于 Firebase,您获取新身份验证提供程序的 AuthCredential,然后使用 link 方法转换帐户:

var credential = firebase.auth.GoogleAuthProvider.credential(
  googleUser.getAuthResponse().id_token);

auth.currentUser.link(credential).then(function(user) {
  console.log("Anonymous account successfully upgraded", user);
}, function(error) {
  console.log("Error upgrading anonymous account", error);
});

这在 AngularFire2 中可行吗?

您没有理由不能使用底层 Firebase API,因为由 AngularFire2 创建的 Firebase App 可用于注入。

您可以使用注入的应用程序访问 AngularFire2 未公开的 auth() (or storage()) 实例的任何方法。

为了示例的目的,您可以像这样将其注入到应用程序组件中:

import { Component, Inject } from "@angular/core";
import { AngularFire, FirebaseApp } from "angularfire2";
import * as firebase from "firebase";

@Component({
  selector: "app",
  template: ...
})
export class AppComponent {

  constructor(
    // Inject AngularFire2:
    private angularFire: AngularFire,
    // Inject the Firebase App instance:
    @Inject(FirebaseApp) private firebaseApp: firebase.app.App
  ) {

    // Perform some sort of login.

    ...

    angularFire.auth.subscribe((state) => {

      // AngularFire2's auth observable will emit when the authentication
      // state changes and if the state is non-null, there will be a
      // current user. At this point, you should be able to do with the
      // injected app what it was you were doing with the SDK.

      if (state) {

        var credential = firebase.auth
          .GoogleAuthProvider
          .credential(googleUser.getAuthResponse().id_token);

        firebaseApp.auth()
          .currentUser
          .link(credential)
          .then((user) => {
            console.log("Anonymous account successfully upgraded", user);
          })
          .catch((error) => {
            console.log("Error upgrading anonymous account", error);
          });
      }
    });
  }
}

您不必使用 auth 可观察对象;您还可以使用 AngularFire2 的 auth.login 方法返回的承诺将代码放入承诺链中。

如以下评论所述,GoogleAuthProvider class 位于 firebase.app 命名空间(而非应用程序实例)中。此外,由于 AngularFire2 在 FirebaseAuthStateauth 属性 中提供了当前用户,因此您无需注入应用程序实例即可执行您想要的操作与 Google 提供商有关。您只需要 firebase 导入:

this.angularFire.auth.login({
  email: "some@address.com",
  password: "password",
})
.then((authState: FirebaseAuthState) => {
  authState.auth.linkWithRedirect(new firebase.auth.GoogleAuthProvider());
});

这是一个工作示例;

import * as firebase from 'firebase':


upgradeAnonymous() {

    let credential = new firebase.auth.GoogleAuthProvider();

    firebase.auth().currentUser.linkWithPopup(credential).then(function(user) {
       console.log("Anonymous account successfully upgraded", user);
      }, function(error) {
        console.log("Error upgrading anonymous account", error);
      })
} 

AngularFire2 v4 中的完整示例。它会将匿名用户升级到 Google 提供程序,并保持相同的身份验证 UID。

import { Component, OnInit } from '@angular/core';
import { AngularFireAuth } from 'angularfire2/auth';
import * as firebase from 'firebase/app';
import { Observable } from 'rxjs/Observable';

@Component({
  selector: 'app-user',
  templateUrl: './user.component.html',
  styleUrls: ['./user.component.scss']
})
export class UserComponent implements OnInit {

  user: Observable<firebase.User>;

  constructor(private afAuth: AngularFireAuth) { }

  ngOnInit() {
    this.user = this.afAuth.authState;
  }

  anonymousLogin() {
    return this.afAuth.auth.signInAnonymously()
  }

  anonymousUpgrade() {
    const provider = new firebase.auth.GoogleAuthProvider()
    firebase.auth().currentUser.linkWithPopup(provider)
  }


}

Thrown if there already exists an account with the email address asserted by the credential. Resolve this by calling firebase.auth.Auth.fetchSignInMethodsForEmail with the error.email and then asking the user to sign in using one of the returned providers. Once the user is signed in, the original credential retrieved from the error.credential can be linked to the user with firebase.User.linkWithCredential to prevent the user from signing in again to the original provider via popup or redirect. If you are using redirects for sign in, save the credential in session storage and then retrieve on redirect and repopulate the credential using for example firebase.auth.GoogleAuthProvider.credential depending on the credential provider id and complete the link.

一个好的解决方案是 ➡️ link multiple auth providers 到一个帐户。用户可以 signup/signin 使用任何方法,我们将对他们进行身份验证并更新他们的记录。因此同一用户可以使用多个身份验证提供程序登录。

 // Sign in with Google
  GoogleAuth() {
    return this.authLogin(new GoogleAuthProvider()).then(() => {});
  }

  // Sign in with GitHub
  GithubAuth() {
    return this.authLogin(new GithubAuthProvider()).then(() => {});
  }

  // Auth logic to run auth providers
  authLogin(provider: any) {
    return this.afAuth
               .signInWithPopup(provider)
               .then((result) => {
                 this.setUserData(result.user).then(() => {
                   this.router.navigate(['dashboard']);
                 });
               })
               .catch(error => {

                 const code = error.code;
                 const credential = error.credential;

                 if (code === 'auth/account-exists-with-different-credential') {
                   // Get other Auth providers user has used before (e.g google.com)
                   this.afAuth.fetchSignInMethodsForEmail(error.email).then(result => {
                     const provider = this.getAuthProvider(result[0]);
                     // Log in the user with other provider used before
                     this.authLogin(provider).then(result => {
                       this.afAuth.authState.pipe(take(1)).subscribe(user => {
                         if (user) {
                           user.linkWithCredential(credential).then(() => {
                             console.log('Credential linked successfully: ', credential);
                           });
                         }
                       });
                     });
                   });
                 }
                 
               });
  }

这里有更多相关信息:https://medium.com/p/8a0f192458f8