Securely query data

This page builds on the concepts in Structuring Security Rules and Writing Conditions for Security Rules to explain how Cloud Firestore Security Rules interact with queries. It takes a closer look at how security rules affect the queries you can write and describes how to ensure your queries use the same constraints as your security rules. This page also describes how to write security rules to allow or deny queries based on query properties like limit and orderBy.

Queries and security rules

When writing queries to retrieve documents, keep in mind that security rules are not filters—queries are all or nothing. To save you time and resources, Cloud Firestore evaluates a query against its potential result set instead of the actual field values for all of your documents. If a query could potentially return documents that the client does not have permission to read, the entire request fails.

As the examples below demonstrate, you must write your queries to fit the constraints of your security rules.

Secure and query documents based on auth.uid

The following example demonstrates how to write a query to retrieve documents protected by a security rule. Consider a database that contains a collection of story documents:

/stories/{storyid}

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

In addition to the title and content fields, each document stores the author and published fields to use for access control. These examples assume the app uses Firebase Authentication to set the author field to the UID of the user who created the document. Firebase Authentication also populates the request.auth variable in the security rules.

The following security rule uses the request.auth and resource.data variables to restrict read and write access for each story to its author:

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;
    }
  }
}

Suppose that your app includes a page that shows the user a list of story documents that they authored. You might expect that you could use the following query to populate this page. However, this query will fail, because it does not include the same constraints as your security rules:

Invalid: Query constraints do not match security rules constraints

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

The query fails even if the current user actually is the author of every story document. The reason for this behavior is that when Cloud Firestore applies your security rules, it evaluates the query against its potential result set, not against the actual properties of documents in your database. If a query could potentially include documents that violate your security rules, the query will fail.

In contrast, the following query succeeds, because it includes the same constraint on the author field as the security rules:

Valid: Query constraints match security rules constraints

var user = firebase.auth().currentUser;

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

Secure and query documents based on a field

To further demonstrate the interaction between queries and rules, the security rules below expand read access for the stories collection to allow any user to read story documents where the published field is set to true.

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;
    }
  }
}

The query for published pages must include the same constraints as the security rules:

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

The query constraint .where("published", "==", true) guarantees that resource.data.published is true for any result. Therefore, this query satisfies the security rules and is allowed to read data.

Evaluating constraints on queries

Your security rules can also accept or deny queries based on their constraints. The request.query variable contains the limit, offset, and orderBy properties of a query. For example, your security rules can deny any query that doesn't limit the maximum number of documents retrieved to a certain range:

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

The following ruleset demonstrates how to write security rules that evaluate constraints placed on queries. This example expands the previous stories ruleset with the following changes:

  • The ruleset separates the read rule into rules for get and list.
  • The get rule restricts retrieval of single documents to public documents or documents the user authored.
  • The list rule applies the same restrictions as get but for queries. It also checks the query limit, then denies any query without a lmit or with a limit greater than 10.
  • The ruleset defines an authorOrPublished() function to avoid code duplication.
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;
    }

  }
}

Next steps

Оставить отзыв о...

Текущей странице
Нужна помощь? Обратитесь в службу поддержки.