用户第二次认证后,使用新的userId更新文档

时间:2019-04-22 16:41:11

标签: firebase firebase-authentication google-cloud-firestore firebase-security-rules

我有以下按预期使用的用例:

  1. 新用户到达网站
  2. 从Firebase匿名登录中为
  3. 用户提供user.uid
  4. 用户创建一个文档,其中包含上述user.uid
  5. 作为userId引用
  6. 在同一页面上邀请用户登录,否则文档将丢失
  7. 用户登录并找到帐户文件

获胜!

现在我有一个用例无法按预期工作:

  1. 返回会话已过期或来自其他浏览器的用户到达网站
  2. 从Firebase匿名登录中为
  3. 用户提供user.uid
  4. 用户创建一个文档,其中包含上述user.uid
  5. 作为userId引用
  6. 在同一页面上邀请用户登录,否则文档将丢失
  7. 用户登录,找不到是帐户文件

这次没有胜利:(

我使用以下配置配置了Firebase身份验证:

const uiConfig = {
  signInFlow: 'popup',
  autoUpgradeAnonymousUsers: true,
  signInOptions: [
    firebase.auth.GoogleAuthProvider.PROVIDER_ID,
  ],
  callbacks: {
    signInFailure: (error: any) => {
      if (error.code != 'firebaseui/anonymous-upgrade-merge-conflict') {
        return Promise.resolve();
      }
      var cred = error.credential;
      return firebase.auth().SignInAndRetrieveDataWithCredential(cred);
    }

  },
};

因此,如您所见,问题在于,autoUpgradeAnonymousUsers第一次使用匿名用户ID创建一个新的userId,一切都很好,但是第二次当然不起作用了。

鉴于我要在安全规则中创建一个无法更新userId并且只有具有相同userId的请求才能看到该文档的检查,我应该如何解决这个问题?

安全规则:

allow create: if request.auth.uid != null
allow read: if request.auth.uid == resource.data.userId 
                    && request.auth.uid != null
allow update: if request.auth.uid == request.resource.data.userId && resource.data.userId == request.resource.data.userId && request.auth.uid != null

谢谢。

1 个答案:

答案 0 :(得分:0)

问题是您无法使用相同的凭据创建新用户。如果用户登录,他将从匿名登录中删除数据。

您必须在本地保存来自匿名用户的数据,并且在用户登录后,必须将数据复制到当前用户。您还应该删除匿名帐户。

我已经找到了使用Firebase实时数据库保存用户数据的示例。

https://github.com/firebase/firebaseui-web#upgrading-anonymous-users

    // signInFailure callback must be provided to handle merge conflicts which
    // occur when an existing credential is linked to an anonymous user.
    signInFailure: function(error) {
      // For merge conflicts, the error.code will be
      // 'firebaseui/anonymous-upgrade-merge-conflict'.
      if (error.code != 'firebaseui/anonymous-upgrade-merge-conflict') {
        return Promise.resolve();
      }
      // The credential the user tried to sign in with.
      var cred = error.credential;
      // If using Firebase Realtime Database. The anonymous user data has to be
      // copied to the non-anonymous user.
      var app = firebase.app();
      // Save anonymous user data first.
      return app.database().ref('users/' + firebase.auth().currentUser.uid)
          .once('value')
          .then(function(snapshot) {
            data = snapshot.val();
            // This will trigger onAuthStateChanged listener which
            // could trigger a redirect to another page.
            // Ensure the upgrade flow is not interrupted by that callback
            // and that this is given enough time to complete before
            // redirection.
            return firebase.auth().signInWithCredential(cred);
          })
          .then(function(user) {
            // Original Anonymous Auth instance now has the new user.
            return app.database().ref('users/' + user.uid).set(data);
          })
          .then(function() {
            // Delete anonymnous user.
            return anonymousUser.delete();
          }).then(function() {
            // Clear data in case a new user signs in, and the state change
            // triggers.
            data = null;
            // FirebaseUI will reset and the UI cleared when this promise
            // resolves.
            // signInSuccessWithAuthResult will not run. Successful sign-in
            // logic has to be run explicitly.
            window.location.assign('<url-to-redirect-to-on-success>');
          });

    }