Join us for Firebase Summit on November 10, 2021. Tune in to learn how Firebase can help you accelerate app development, release with confidence, and scale with ease. Register

构建 Cloud Firestore 安全规则

借助 Cloud Firestore 安全规则,您可以控制对数据库中的文档和集合的访问权限。您可以使用灵活的规则语法创建与任意情况(包括对整个数据库执行的所有写入操作和对特定文档的操作)匹配的规则。

本指南介绍安全规则的基本语法和结构。将此语法与安全规则条件结合使用可创建完整的规则集。

服务和数据库声明

Cloud Firestore 安全规则始终以以下声明开头:

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

service cloud.firestore 声明将规则限制为在 Cloud Firestore 范围内有效,以防止 Cloud Firestore 安全规则与其他产品(例如 Cloud Storage)的规则发生冲突。

match /databases/{database}/documents 声明指定规则应该与项目中的所有 Cloud Firestore 数据库都匹配。目前,每个项目只有一个数据库,名为 (default)

基本的读取/写入规则

基本规则由一个 match 语句(指定文档路径)和一个 allow 表达式(详细说明何时允许读取指定的数据)构成:

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

    // Match any document in the 'cities' collection
    match /cities/{city} {
      allow read: if <condition>;
      allow write: if <condition>;
    }
  }
}

所有 match 语句都应指向文档,而不是集合。Match 语句可以指向特定的文档(如 match /cities/SF),也可以使用通配符指向指定路径下的任意文档(如 match /cities/{city})。

在上面的示例中,match 语句使用了 {city} 通配符语法。这意味着相应规则适用于 cities 集合中的任何文档(例如 /cities/SF/cities/NYC)。在对 match 语句中的 allow 表达式求值时,city 变量将解析为城市文档名称(例如 SFNYC)。

细化的操作

在某些情况下,将 readwrite 细分为更细化的操作很有用。例如,您的应用可能希望对文档创建(而非文档删除)强制执行不同的条件。或者,您可能希望允许单个文档读取,但拒绝大量查询。

read 规则可以细分为 getlist,而 write 规则可以细分为 createupdatedelete

service cloud.firestore {
  match /databases/{database}/documents {
    // A read rule can be divided into get and list rules
    match /cities/{city} {
      // Applies to single document read requests
      allow get: if <condition>;

      // Applies to queries and collection read requests
      allow list: if <condition>;
    }

    // A write rule can be divided into create, update, and delete rules
    match /cities/{city} {
      // Applies to writes to nonexistent documents
      allow create: if <condition>;

      // Applies to writes to existing documents
      allow update: if <condition>;

      // Applies to delete operations
      allow delete: if <condition>;
    }
  }
}

分层数据

Cloud Firestore 中的数据以文档集合的形式出现,每个文档可以通过子集合来扩展这种层次结构。了解安全规则如何与分层数据进行交互是非常重要的。

假设 cities 集合中的每个文档都包含一个 landmarks 子集合。由于安全规则仅适用于匹配的路径,因此在 cities 集合上定义的访问权限控制不适用于 landmarks 子集合。不过,您可以编写明确的规则来控制对子集合的访问:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      allow read, write: if <condition>;

        // Explicitly define rules for the 'landmarks' subcollection
        match /landmarks/{landmark} {
          allow read, write: if <condition>;
        }
    }
  }
}

嵌套 match 语句时,内层 match 语句的路径始终是相对于外层 match 语句的路径而言的。因此,以下规则集是等效的:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}
service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city}/landmarks/{landmark} {
      allow read, write: if <condition>;
    }
  }
}

递归通配符

如果您要将规则应用于任意深度的层次结构,请使用递归通配符语法 {name=**}:例如:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

使用递归通配符语法时,通配符变量将包含整个匹配的路径段,即使相应文档位于多层嵌套的子集合中也是如此。例如,上面列出的规则将与位于 /cities/SF/landmarks/coit_tower 中的文档匹配,document 变量的值将是 SF/landmarks/coit_tower

但请注意,递归通配符的行为取决于规则版本。

版本 1

安全规则默认使用版本 1。在版本 1 中,递归通配符与一个或多个路径项匹配。它们不能与空路径匹配,因此 match /cities/{city}/{document=**} 将与子集合(而非 cities 集合)中的文档匹配,而 match /cities/{document=**} 将同时与 cities 集合和子集合中的文档匹配。

递归通配符必须位于匹配语句的末尾。

版本 2

在安全规则的版本 2 中,递归通配符与零个或更多路径项匹配。match/cities/{city}/{document=**} 将与任何子集合中的文档以及 cities 集合中的文档匹配。

您必须通过将 rules_version = '2'; 添加到安全规则的第一行来选择启用版本 2:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{city}/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

您最多只能在每个匹配语句中使用一个递归通配符,但在版本 2 中,可以将此通配符放在匹配语句的任何位置。例如:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the songs collection group
    match /{path=**}/songs/{song} {
      allow read, write: if <condition>;
    }
  }
}

如果您使用集合组查询,必须使用版本 2。请参阅保护集合组查询

重叠的匹配语句

某个文档可以与多个 match 语句匹配。如果有多个 allow 表达式与某个请求匹配,则只要任何一个条件为 true,就允许访问:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the 'cities' collection.
    match /cities/{city} {
      allow read, write: if false;
    }

    // Matches any document in the 'cities' collection or subcollections.
    match /cities/{document=**} {
      allow read, write: if true;
    }
  }
}

在上面的示例中,因为第二个规则始终为 true,所以系统允许对 cities 集合进行所有读写操作,即使第一个规则始终为 false 也是如此。

安全规则限制

在处理安全规则时,请注意以下限制:

限制 详细信息
每个请求调用 exists()get()getAfter() 的最大次数
  • 10 - 对于单文档请求和查询请求。
  • 20 - 对于多文档读取、事务和批量写入。前面的 10 次限制也适用于每个操作。

    例如,假设您创建了一个包含 3 次写入操作的批量写入请求,并且您的安全规则使用 2 次文档访问调用来验证每次写入。在此情况下,每次写入会使用 10 次访问调用限额中的 2 次调用,而批量写入请求则会使用 20 次访问调用限额中的 6 次调用。

超过任一限制都会导致权限被拒绝的错误。

某些文档访问调用可能会被缓存,缓存的调用不会计入限额。

嵌套 match 语句深度上限 10
在路径段中,可在一组嵌套 match 语句中使用的路径长度上限 100
可在一组嵌套 match 语句中使用的路径捕获变量数上限 20
函数调用深度上限 20
函数参数的数量上限 7
每个函数的 let 变量绑定数上限 10
递归或循环函数调用次数上限 0(不允许)
每个请求中评估的表达式数量上限 1000
规则集的大小上限 规则集必须符合以下两种大小限制:
  • 对于从 Firebase 控制台或使用 firebase deploy 从 CLI 发布的规则集文本源,其大小不得超过 256 KB。
  • 对于 Firebase 处理该源并在后端上将其激活时生成的编译规则集,其大小不得超过 250 KB。

后续步骤