使用firestore创建安全的类似REST的API

时间:2017-10-05 16:44:09

标签: javascript firebase google-cloud-firestore

我想在firebase firestore中存储一对多关系。我们假设我有一位作者,并且有一些属于这位作者的书籍。我可以将它存储在嵌套关系中:

author/
  authorId1 : {
    books: [{...}, {...}]
  }

但是我还需要一种方法来列出所有书籍,最好不要遍历每一位作者(与实时数据库有所需要),所以我想我应该这样做

author/
  authorId1 : {
    books: [bookId1, bookId2]
  }
books/
  bookId1: {...}
  bookId2: {...}

但出于安全和性能方面的原因,我宁愿不在前端进行过滤。我发现可以编写查询:

const bookRef = fireStore.collection('books');
debtorsRef.where('author', '==', authorId).then(...);

这有望消除性能问题,但它不安全,因为它可以从客户端获取其他作者的书籍。另外,我宁愿将关系存储在作者文档中,而不是相反。

在一个宁静的API上,例如Django Rest Framework,我限制查询集只返回属于给定用户的书籍。 IIUC可以使用IAM,但根据示例我不太确定如何。

所以,再次,我只有在其作者的书籍属性中列出其ID时才会返回该书。理论上,一本书可能属于多位作者。

我想这是重复的,很多人都有这个问题,但我找不到这个特定用例的明确答案。

1 个答案:

答案 0 :(得分:2)

您可以编写Security Rules来正确保护您的查询:

service cloud.firestore {
  match /databases/{database}/documents {
    match /books/{bookId} {
      allow read: if request.resource.data.author == resource.data.author
    }
  }
}

请注意,目前我们仅支持对平等的约束(==),而不支持不等式(!=<<=等。

您可以扩展此概念以维护每本书的子集合中的所有者列表,并进行存在性检查(使用exists()函数):

service cloud.firestore {
  match /databases/{database}/documents {
    match /books/{bookId} {
      allow read: if exists(/databases/$(database)/documents/books/$(bookId)/owners/$(request.auth.uid))
      match /owners/{ownerId} {
        // Include other conditions that provide for ownership checks
        allow write: if request.auth.uid == ownerId;
      }
    }
  }
}