安全查询数据

本页面以设计安全规则结构编写安全规则的条件中的概念为基础,介绍 Cloud Firestore 安全规则与查询之间的相互作用。其中将更详细地介绍安全规则如何影响您可以编写的查询,以及如何确保您的查询与安全规则使用相同的限制条件。本页面还介绍了如何编写安全规则,以根据查询的属性(如 limitorderBy)允许或拒绝查询。

查询和安全规则

在编写查询以检索文档时,请务必留意,安全规则不是过滤器 - 查询结果要么包含全部,要么什么也没有。为了节省时间和资源,Cloud Firestore 会针对查询的可能结果集(而不是您所有文档的实际字段值)来对其进行评估。如果查询可能会返回客户端无权读取的文档,则整个请求将会失败。

如下例所示,您编写的查询必须满足您的安全规则的限制条件。

根据 auth.uid 来保护和查询文档

以下示例演示了如何编写查询以检索受安全规则保护的文档。假设某数据库包含了一个 story 文档的集合:

/stories/{storyid}

{
  title: "A Great Story",
  content: "Once upon a time...",
  author: "some_auth_id",
  published: false
}

除了 titlecontent 字段之外,每个文档还存储了用于控制访问的 authorpublished 字段。这些示例假定应用使用 Firebase 身份验证author 字段设置为创建文档的用户的 UID。Firebase 身份验证还会填充安全规则中的 request.auth 变量。

以下安全规则使用 request.authresource.data 变量限定每个 story 的读写权限仅归其作者所有:

service cloud.firestore {
  match /databases/{database}/documents {
    match /stories/{storyid} {
      // Only the authenticated user who authored the document can read or write
      allow read, write: if request.auth.uid == resource.data.author;
    }
  }
}

假设您的应用包含一个页面,其中向用户列出他们所创建的 story 文档。您也许会认为,可以使用以下查询来填充此页面。但是,由于没有包含与您的安全规则相同的限制条件,此查询将会失败:

无效:查询限制条件与安全规则限制条件不匹配

// This query will fail
db.collection("stories").get()

即使当前用户实际上是所有 story 文档的作者,查询也会失败。造成这种情况的原因是,当 Cloud Firestore 应用您的安全规则时,它会针对可能的结果集评估查询,而不是针对数据库中文档的实际属性进行评估。如果查询可能包括违反安全规则的文档,则查询将会失败。

相反,由于在 author 字段中包含了与安全规则相同的限制条件,以下查询将会成功:

有效:查询和安全规则的限制条件匹配

var user = firebase.auth().currentUser;

db.collection("stories").where("author", "==", user.uid).get()

根据字段来保护和查询文档

为了进一步演示查询和规则之间的相互作用,下面的安全规则扩展了 stories 集合的读取权限,以允许任意用户读取 published 字段设置为 truestory 文档。

service cloud.firestore {
  match /databases/{database}/documents {
    match /stories/{storyid} {
      // Anyone can read a published story; only story authors can read unpublished stories
      allow read: if resource.data.published == true || request.auth.uid == resource.data.author;
      // Only story authors can write
      allow write: if request.auth.uid == resource.data.author;
    }
  }
}

针对已发布页面的查询必须包含与安全规则相同的限制条件:

db.collection("stories").where("published", "==", true).get()

查询限制条件 .where("published", "==", true) 确保了 resource.data.published 对于任何结果都为 true。因此,该查询满足安全规则,可用于读取数据。

评估查询的限制条件

您的安全规则也可以根据查询的限制条件接受或拒绝查询。request.query 变量包含查询的 limitoffsetorderBy 属性。例如,如果查询没有将检索到的文档数量上限限制为特定范围,那么您的安全规则可以拒绝该查询:

allow list: if request.query.limit <= 10;

以下规则集演示了如何编写会评估查询的限制条件的安全规则。此示例扩展了上述 stories 规则集,并进行了以下更改:

  • 该规则集将读取规则拆分成了 get 规则和 list 规则。
  • get 规则将针对单个文档的检索限定为公开文档或用户编写的文档。
  • list 规则会应用与 get 规则相同的限制条件,但应用对象为查询。它还会检查查询的限制,并拒绝没有设置数量限制或数量限制大于 10 的查询。
  • 该规则集定义了一个 authorOrPublished() 函数以避免代码重复。
service cloud.firestore {

  match /databases/{database}/documents {

    match /stories/{storyid} {

      // Returns `true` if the requested story is 'published'
      // or the user authored the story
      function authorOrPublished() {
        return resource.data.published == true || request.auth.uid == resource.data.author;
      }

      // Deny any query not limited to 10 or fewer documents
      // Anyone can query published stories
      // Authors can query their unpublished stories
      allow list: if request.query.limit <= 10 &&
                     authorOrPublished();

      // Anyone can retrieve a published story
      // Only a story's author can retrieve an unpublished story
      allow get: if authorOrPublished();

      // Only a story's authors can write to a story
      allow write: if request.auth.uid == resource.data.author;
    }

  }
}

后续步骤

发送以下问题的反馈:

此网页
需要帮助?请访问我们的支持页面