Angularfire2 显示 "Missing permissions"错误,而直接运行 firebase 没有问题

标签 angular firebase angularfire2 angularfire firebase-security

AngularFire2 似乎以不同于纯 firebase sdk 的方式处理权限。

重现此问题的步骤:

  • 登录用户帐户
  • 调用以检索用户的 firestore 文档:
return this.afStore.doc('users/' + authId).valueChanges()
  .pipe(map(u => {
    if (u) {
      return new User(u);
    }
    return null;
  })
);
  • 注销该用户帐户,然后登录到另一个用户帐户
  • 进行相同的调用以检索新用户的 firestore 文档
  • 这次是返回一个Missing or insufficient permissions错误

如果我将 firebase 的代码直接添加到我的 index.html 文件中,它仍然可以工作:

var email = "xxx@xxx.com";
var password = "xxx";
var firebaseConfig = {...};

firebase.initializeApp(firebaseConfig);

firebase.auth().onAuthStateChanged((u) => {
  if (u) {
    firebase.firestore().doc('users/' + u.uid).get()
      .then(u => console.log("Got favorites", u.data()));
    firebase.firestore().doc('favorites/' + u.uid).get()
      .then(u => console.log("Got favorites", u.data()));
  }
});

firebase.auth().signInWithEmailAndPassword(email, password).then(cred => {
  console.log("Signed in", cred)
})

我的 firebase 规则如下,但它们在模拟器中似乎没问题,而且显然有时在前端工作:

service cloud.firestore {
  match /databases/{database}/documents {

    function internalGetUserFromReq() {
      return get(/databases/$(database)/documents/users/$(request.auth.uid))
    }

    //...

    match /users/{userID} {
      allow read, write: if internalGetUserFromReq().data.authId == userID;
      allow read, write: if internalGetUserFromReq().data.role == 0;
    }
}

完整实现

为了更完整的图片,这是我的登录方法:

this.afAuth.auth.signInWithEmailAndPassword(email, password).then((cred: firebase.auth.UserCredential) => {
  return this.user$;
}).catch((err: Error) => {
  this.logout();
  throw new Error(err.message);
});

我这样退出:

return this.afAuth.auth.signOut().then(() => {
  this.appState.clean();
  return this.router.navigate(['']);
});

我正在像这样收听 Firebase AuthState:

this.user$ = this.afAuth.authState.pipe(switchMap((user: firebase.User) => {
  if (user) {
    return this.getUser().pipe(catchError((err: Error) => {
      this.logout();
      return throwError(err);
    }));
  }
  return of(null);
})).pipe(share());

switchMap 中引用的 getUser() 方法是我在问题顶部粘贴的原始方法,仅返回属于该用户的文档的可观察对象(例如 users/12345).

回顾

回顾一下这个问题,登录/注销和 AuthState 观察器都按预期运行,但我在将 firebase 规则添加到我的 Firestore 文档时会限制用户只能访问他们自己的文档(即 authIDrequest.auth.uid) 匹配,则文档将无法访问。此行为仅通过 AngularFire2 包发生,并且在页面重新加载后仍然存在,甚至在具有干净 cookie 和缓存的全新浏览器中打开应用程序时仍然存在。

解决方法

对于遇到此问题的任何其他人,我不得不删除 AngularFire2(这同样适用于新的 @angular/fire 包)并将其替换为我自己的核心 firebase 包的包装器。

繁殖

我目前无法创建复制品 - 我知道这很烦人,当我有更多时间时我会尝试做一个。然而,这个问题在 AngularFire2 中根深蒂固,我将不得不创建一个新的 Angular 应用程序,设置一个新的 Firebase 实例,完成身份验证、Firestore 数据库和文档访问规则,然后还实现完整的用户登录过程。为了公正地对待这个问题,我还需要再次设置相同但没有 AngularFire2,只是为了证明是那个包导致了问题。在我难得的休息日里塞满工作对我来说太多了!

如果有人有时间修补并想设置一个,请给我留言,我很乐意提供帮助。

最佳答案

当你登录时,你得到了 firebase auth 用户,你获取它的 Id,然后你从数据库订阅用户文档,可能你正在使用 2 订阅,一个是 auth,第二个是用户完整文档(我们在这里看不到完整的身份验证代码),现在当您注销时,您的用户文档订阅仍在运行,但您现在没有权限获取用户完整文档,因为您不再登录(和规则是关于 auth 用户的),我的解决方案是将 switchMap 与 angularFire auth 一起使用,因此只有一个订阅(这实际上是您在后面的代码中所做的 - 仅在 html 中)

** 您的错误可能是因为注销而不是新登录

private _sub: Subscription;

constructor(private _auth: AngularFireAuth, private _db: AngularFirestore){
     this._sub = this._auth.authState
        .pipe(
            switchMap(u => (u)
                ? this._db.collection('Users).doc(u.uid)
                    .valueChanges()
                : of(null))
        .subscribe(user => {
           // some actions
            });
}

现在,当您注销时,firebase 将不会尝试再次获取用户文档并出现此错误

关于Angularfire2 显示 "Missing permissions"错误,而直接运行 firebase 没有问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56728210/

相关文章:

angular - 如何修复 - 类型 'map' 上不存在属性 'Action'

angular - 在组件文件中导入 FormsModule 和 ReactiveFormsModule

swift - 如何将 Firestore 文档映射到结构?

ANGULAR 2 - 组件共享数据服务

android - Flutter 2.0 与 Firebase 云消息传递 : onMessage not called on Android

java - 从 Firebase 检索一些数据并将其放在 RecyclerView 上

firebase - AngularFire2 在数组中嵌套 *ngFor 数组...但 Firebase 没有数组...?

angular - 无法使用 DocumentSnapshot 中的属性 data()

angular - 如何更新 Angular 库项目?

angular - 如何在 Angular 自定义组件中一起添加 ngModel 和 formControlName?