【问题标题】:Firestore Rules for Roles and Users角色和用户的 Firestore 规则
【发布时间】:2018-05-14 06:42:59
【问题描述】:

我正在尝试在我的 firestore 数据库中构建类似基于角色的访问 (https://firebase.google.com/docs/firestore/solutions/role-based-access)。但是像我定义的角色不起作用。我总是收到错误

Missing or insufficient permissions.

到目前为止,我的 Firestore 规则中有以下内容:

service cloud.firestore {
  match /databases/{database}/documents {
  
    function isSignedIn() {
      return request.auth != null;
    }

    function getRole(rsc) {
      return rsc.data.roles[request.auth.uid];
    }

    function isOneOfRoles(rsc, array) {
      return isSignedIn() && (getRole(rsc) in array) || isSignedIn() && rsc.data.openWorld == true;
    }
  	
    match /users/{user} {
      allow read: if isSignedIn() && request.auth.uid == resource.data.uid;
    }
 
    // Match any document in the 'worlds' collection
    match /worlds/{world} {
      allow read: if isOneOfRoles(resource, ['owner', 'writer', 'commenter', 'reader']);
    }
  }
}

我的文档结构如下:ROOT/worlds/{WORLDID}/... 以及其中的每个文档如下:

{
  name: "Open World",
  desc: "", 
  openWorld: true,
  roles: {
    DzpqsN6QjmZoCoM0eymWJ17VKbG3: "owner"
  }
}

我将它与 Angular Frontedn 和 Angularfire 一起使用,其中包含以下代码,这些代码被包装到服务中:

getWorlds(userId): Observable<any> {
  return this.afs.collection('worlds').snapshotChanges().map(actions => {
      return actions.map(a => {
        const data = a.payload.doc.data();
        const id = a.payload.doc.id;
        return { id, ...data };
      });
    }).catch((e: any) => Observable.throw(this.errorHandler(e)));
}

任何人都可以看到那里可能存在错误,或者此时 Firestore 是否存在一般错误?谢谢!

【问题讨论】:

  • 您还应该包括用于测试的读/写数据/代码。

标签: javascript firebase google-cloud-firestore


【解决方案1】:

根据您的评论进行编辑:

您的查询失败“因为它不包含与您的安全规则相同的约束”。见https://firebase.google.com/docs/firestore/security/rules-query#secure_and_query_documents_based_on_authuid

换句话说,您不能仅依靠安全规则过滤用户可以阅读的文档,您必须相应地构建查询。但是,这对于您当前的数据结构是不可能的,因为 Firestore 不支持逻辑 OR 查询(例如,以下将不可能是 owner OR writer、owner OR openWorld 等)。


我已经彻底测试了您的规则,它们似乎在所有情况下都能正常工作,即使用不同的角色,在openWorld = true 的情况下,并且没有声明正确的角色,在openWorld = false 的情况下等等。是您确定您的用户已正确登录?您是否等待足够的时间让规则“传播”?

这是用于测试的 JavaScript 代码

var docRef = firestoredb.collection("worlds").doc("x9fwf0Wi528OBlGYIZz1");

firebase.auth().signInWithEmailAndPassword("xxxx@xxx.com", "xxxxx")
    .then(function(userCredential) {

   docRef.get().then(function(doc) {
      if (doc.exists) {
          console.log("Document data:", doc.data());

      } else {
          // doc.data() will be undefined in this case
          console.log("No such document!");
      }

   }).catch(function(error) {
      console.log("Error getting document:", error);
   });

});

最后,这里有一个建议:我可能会重构您的规则,将isOneOfRolesisOpenWorld 的情况分开,例如:

    function isOneOfRoles(rsc, array) {
      return isSignedIn() && (getRole(rsc) in array);
    }

    function isOpenWorld(rsc) {
      return isSignedIn() && rsc.data.openWorld == true;
    }

   .....

    // Match any document in the 'worlds' collection
    match /worlds/{world} {
      allow read: if isOneOfRoles(resource, ['owner', 'writer', 'commenter', 'reader']) || isOpenWorld(resource);
    }

【讨论】:

  • @AndréKool 你可能是对的,我真的不知道...... OP 询问“任何人都可以看到那里可能有错误,或者此时 Firestore 是否存在一般错误?”。如果您认为我应该删除它,我可以这样做。
  • 我会把这个决定留给 OP。他们可以最好地确定您的帖子的有用性。
  • 是的,我等待了足够的时间(超过 10 分钟)让我的规则生效。当我仅使用 isSignedIn() 测试我的代码时,它正在工作。因此,我认为错误出在 getRole() 函数中。它可能来自我对集合本身的调用(我将它插入到原始问题中)?我想查询所有条目,用户被允许,而不是一个特定的。
  • 好的,谢谢!我明白了问题所在。但是我怎么能在我的前端脚本中做到这一点。我必须写一个 where 条件,检查当前用户是否是我的 .roles 集的一部分。类似于以下内容: ref.where("roles", "contains", user.uid)
  • 看看这个 SO 帖子的第一个答案:stackoverflow.com/questions/46568142/…。但是这种方法会要求您保留四个对象,每个角色一个对象并执行多个查询。我认为无论如何你都必须改变你的数据模型。
猜你喜欢
  • 2020-11-28
  • 1970-01-01
  • 2019-06-15
  • 2020-05-23
  • 1970-01-01
  • 2021-11-14
  • 1970-01-01
  • 1970-01-01
  • 2020-11-27
相关资源
最近更新 更多