Firebase 安全规则利用支持各种复杂性和粒度的灵活、强大的自定义语言。您可以根据对您的应用程序的意义使您的规则具体化或通用化。实时数据库规则使用的语法类似于 JSON 结构中的 JavaScript。 Cloud Firestore 和 Cloud Storage 规则使用基于通用表达语言 (CEL)的语言,该语言构建于 CEL 之上,具有match
和allow
语句,支持有条件地授予访问权限。
但是,由于这些是自定义语言,因此存在学习曲线。当您深入研究更复杂的规则时,使用本指南可以更好地理解规则语言。
选择一个产品以了解有关其规则的更多信息。
基本结构
云端 Firestore
Cloud Firestore 和 Cloud Storage 中的 Firebase 安全规则使用以下结构和语法:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
在构建规则时,了解以下关键概念很重要:
- Request:在
allow
语句中调用的一个或多个方法。这些是您允许运行的方法。标准方法是:get
、list
、create
、update
和delete
。read
和write
便利方法支持对指定数据库或存储路径进行广泛的读取和写入访问。 - 路径:数据库或存储位置,表示为 URI 路径。
- 规则:
allow
语句,其中包含一个条件,如果它的计算结果为真,则允许请求。
下面将更详细地描述这些概念中的每一个。
云储存
Cloud Firestore 和 Cloud Storage 中的 Firebase 安全规则使用以下结构和语法:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
在构建规则时,了解以下关键概念很重要:
- Request:在
allow
语句中调用的一个或多个方法。这些是您允许运行的方法。标准方法是:get
、list
、create
、update
和delete
。read
和write
便利方法支持对指定数据库或存储路径进行广泛的读取和写入访问。 - 路径:数据库或存储位置,表示为 URI 路径。
- 规则:
allow
语句,其中包含一个条件,如果它的计算结果为真,则允许请求。
下面将更详细地描述这些概念中的每一个。
实时数据库
在实时数据库中,Firebase 安全规则由 JSON 文档中包含的类似 JavaScript 的表达式组成。
他们使用以下语法:
{
"rules": {
"<<path>>": {
// Allow the request if the condition for each method is true.
".read": <<condition>>,
".write": <<condition>>,
".validate": <<condition>>
}
}
}
该规则包含三个基本要素:
- 路径:数据库位置。这反映了数据库的 JSON 结构。
- 请求:这些是规则用于授予访问权限的方法。
read
和write
规则授予广泛的读取和写入访问权限,而validate
规则充当辅助验证以根据传入或现有数据授予访问权限。 - 条件:如果计算结果为真,则允许请求的条件。
规则构造
云端 Firestore
Cloud Firestore 和 Cloud Storage 中规则的基本元素如下:
-
service
声明:声明规则适用的 Firebase 产品。 -
match
块:定义规则适用的数据库或存储桶中的路径。 -
allow
语句:提供授予访问权限的条件,以方法区分。支持的方法包括:get
、list
、create
、update
、delete
以及便捷方法read
和write
。 - 可选
function
声明:提供组合和包装条件以跨多个规则使用的能力。
该service
包含一个或多个带有allow
语句的match
块,这些语句提供授予请求访问权限的条件。 request
和resource
变量可用于规则条件。 Firebase 安全规则语言还支持function
声明。
语法版本
syntax
语句指示用于编写源代码的 Firebase 规则语言的版本。该语言的最新版本是v2
。
rules_version = '2';
service cloud.firestore {
...
}
如果未提供rules_version
语句,您的规则将使用v1
引擎进行评估。
服务
service
声明定义了您的规则适用于哪个 Firebase 产品或服务。每个源文件只能包含一个service
声明。
云端 Firestore
service cloud.firestore {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
云储存
service firebase.storage {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
如果您使用 Firebase CLI 为 Cloud Firestore 和 Cloud Storage 定义规则,则必须在单独的文件中维护它们。
匹配
match
块声明一个path
模式,该模式与请求操作的路径(传入的request.path
)相匹配。 match
的主体必须有一个或多个嵌套的match
块、 allow
语句或function
声明。嵌套match
块中的路径是相对于父match
块中的路径的。
path
模式是一个类似于目录的名称,可以包含变量或通配符。 path
模式允许单路径段和多路径段匹配。 path
中绑定的任何变量在match
范围或声明path
的任何嵌套范围内都是可见的。
与path
模式的匹配可能是部分的或完整的:
- 部分匹配:
path
模式是request.path
的前缀匹配。 - 完全匹配:
path
模式匹配整个request.path
。
当进行完全匹配时,将评估块内的规则。当进行部分匹配时,将测试嵌套match
规则以查看是否有任何嵌套path
将完成匹配。
评估每个完整match
中的规则以确定是否允许该请求。如果任何匹配规则授予访问权限,则请求被允许。如果没有匹配的规则授予访问权限,则该请求将被拒绝。
// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
// Partial match.
match /example/{singleSegment} { // `singleSegment` == 'hello'
allow write; // Write rule not evaluated.
// Complete match.
match /nested/path { // `singleSegment` visible in scope.
allow read; // Read rule is evaluated.
}
}
// Complete match.
match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
allow read; // Read rule is evaluated.
}
}
如上例所示, path
声明支持以下变量:
- 单段通配符:通配符变量是通过将变量括在花括号中来在路径中声明的:
{variable}
。该变量可以在match
语句中作为string
访问。 - 递归通配符:递归或多段通配符匹配路径上或路径下的多个路径段。此通配符匹配您设置的位置下方的所有路径。您可以通过在段变量的末尾添加
=**
字符串来声明它:{variable=**}
。该变量可以作为path
对象在match
语句中访问。
允许
match
块包含一个或多个allow
语句。这些是您的实际规则。您可以将allow
规则应用于一种或多种方法。 allow
语句的条件必须评估为 true,Cloud Firestore 或 Cloud Storage 才能授予任何传入请求。您还可以编写不带条件的allow
语句,例如allow read
。但是,如果allow
语句不包含条件,它总是允许对该方法的请求。
如果满足该方法的任何allow
规则,则允许该请求。此外,如果更广泛的规则授予访问权限,则规则授予访问权限并忽略可能限制访问的任何更细化的规则。
考虑以下示例,其中任何用户都可以读取或删除他们自己的任何文件。如果请求写入的用户拥有文件并且文件是 PNG,则更细化的规则仅允许写入。用户可以删除子路径中的任何文件——即使它们不是 PNG——因为之前的规则允许这样做。
service firebase.storage {
// Allow the requestor to read or delete any resource on a path under the
// user directory.
match /users/{userId}/{anyUserFile=**} {
allow read, delete: if request.auth != null && request.auth.uid == userId;
}
// Allow the requestor to create or update their own images.
// When 'request.method' == 'delete' this rule and the one matching
// any path under the user directory would both match and the `delete`
// would be permitted.
match /users/{userId}/images/{imageId} {
// Whether to permit the request depends on the logical OR of all
// matched rules. This means that even if this rule did not explicitly
// allow the 'delete' the earlier rule would have.
allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
}
}
方法
每个allow
语句都包含一个方法,该方法为同一方法的传入请求授予访问权限。
方法 | 请求类型 |
---|---|
便捷方法 | |
read | 任何类型的读取请求 |
write | 任何类型的写请求 |
标准方法 | |
get | 读取单个文档或文件的请求 |
list | 读取查询和集合请求 |
create | 编写新文档或文件 |
update | 写入现有数据库文档或更新文件元数据 |
delete | 删除数据 |
您不能在同一match
块中重叠读取方法,也不能在同一path
声明中重叠写入方法。
例如,以下规则将失败:
service bad.example {
match /rules/with/overlapping/methods {
// This rule allows reads to all authenticated users
allow read: if request.auth != null;
match another/subpath {
// This secondary, more specific read rule causes an error
allow get: if request.auth != null && request.auth.uid == "me";
// Overlapping write methods in the same path cause an error as well
allow write: if request.auth != null;
allow create: if request.auth != null && request.auth.uid == "me";
}
}
}
功能
随着您的安全规则变得越来越复杂,您可能希望将条件集包装在可以在您的规则集中重复使用的函数中。安全规则支持自定义函数。自定义函数的语法有点像 JavaScript,但安全规则函数是用具有一些重要限制的特定领域语言编写的:
- 函数只能包含一个
return
语句。它们不能包含任何附加逻辑。例如,它们不能执行循环或调用外部服务。 - 函数可以从定义它们的范围内自动访问函数和变量。例如,
service cloud.firestore
范围内定义的函数可以访问resource
变量和内置函数,例如get()
和exists()
。 - 函数可以调用其他函数但不能递归。总调用堆栈深度限制为 20。
- 在规则版本
v2
中,函数可以使用let
关键字定义变量。函数最多可以有 10 个 let 绑定,但必须以 return 语句结尾。
函数使用function
关键字定义,并接受零个或多个参数。例如,您可能希望将上面示例中使用的两种类型的条件组合到一个函数中:
service cloud.firestore {
match /databases/{database}/documents {
// True if the user is signed in or the requested data is 'public'
function signedInOrPublic() {
return request.auth.uid != null || resource.data.visibility == 'public';
}
match /cities/{city} {
allow read, write: if signedInOrPublic();
}
match /users/{user} {
allow read, write: if signedInOrPublic();
}
}
}
这是一个显示函数参数和 let 赋值的示例。 let 赋值语句必须用分号分隔。
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
return isAuthor || isAdmin;
}
请注意isAdmin
分配如何强制查找管理员集合。对于不需要不需要的查找的懒惰评估,利用&&
(AND) 和||
的短路特性(或)仅当isAuthor
显示为真(对于&&
比较)或假(对于||
比较)时才调用第二个函数的比较。
function isAdmin(userId) {
return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
// `||` is short-circuiting; isAdmin called only if isAuthor == false.
return isAuthor || isAdmin(userId);
}
随着规则复杂性的增加,在安全规则中使用函数可以使它们更易于维护。
云储存
Cloud Firestore 和 Cloud Storage 中规则的基本元素如下:
-
service
声明:声明规则适用的 Firebase 产品。 -
match
块:定义规则适用的数据库或存储桶中的路径。 -
allow
语句:提供授予访问权限的条件,以方法区分。支持的方法包括:get
、list
、create
、update
、delete
以及便捷方法read
和write
。 - 可选
function
声明:提供组合和包装条件以跨多个规则使用的能力。
该service
包含一个或多个带有allow
语句的match
块,这些语句提供授予请求访问权限的条件。 request
和resource
变量可用于规则条件。 Firebase 安全规则语言还支持function
声明。
语法版本
syntax
语句指示用于编写源代码的 Firebase 规则语言的版本。该语言的最新版本是v2
。
rules_version = '2';
service cloud.firestore {
...
}
如果未提供rules_version
语句,您的规则将使用v1
引擎进行评估。
服务
service
声明定义了您的规则适用于哪个 Firebase 产品或服务。每个源文件只能包含一个service
声明。
云端 Firestore
service cloud.firestore {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
云储存
service firebase.storage {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
如果您使用 Firebase CLI 为 Cloud Firestore 和 Cloud Storage 定义规则,则必须在单独的文件中维护它们。
匹配
match
块声明一个path
模式,该模式与请求操作的路径(传入的request.path
)相匹配。 match
的主体必须有一个或多个嵌套的match
块、 allow
语句或function
声明。嵌套match
块中的路径是相对于父match
块中的路径的。
path
模式是一个类似于目录的名称,可以包含变量或通配符。 path
模式允许单路径段和多路径段匹配。 path
中绑定的任何变量在match
范围或声明path
的任何嵌套范围内都是可见的。
与path
模式的匹配可能是部分的或完整的:
- 部分匹配:
path
模式是request.path
的前缀匹配。 - 完全匹配:
path
模式匹配整个request.path
。
当进行完全匹配时,将评估块内的规则。当进行部分匹配时,将测试嵌套match
规则以查看是否有任何嵌套path
将完成匹配。
评估每个完整match
中的规则以确定是否允许该请求。如果任何匹配规则授予访问权限,则请求被允许。如果没有匹配的规则授予访问权限,则该请求将被拒绝。
// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
// Partial match.
match /example/{singleSegment} { // `singleSegment` == 'hello'
allow write; // Write rule not evaluated.
// Complete match.
match /nested/path { // `singleSegment` visible in scope.
allow read; // Read rule is evaluated.
}
}
// Complete match.
match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
allow read; // Read rule is evaluated.
}
}
如上例所示, path
声明支持以下变量:
- 单段通配符:通配符变量是通过将变量括在花括号中来在路径中声明的:
{variable}
。该变量可以在match
语句中作为string
访问。 - 递归通配符:递归或多段通配符匹配路径上或路径下的多个路径段。此通配符匹配您设置的位置下方的所有路径。您可以通过在段变量的末尾添加
=**
字符串来声明它:{variable=**}
。该变量可以作为path
对象在match
语句中访问。
允许
match
块包含一个或多个allow
语句。这些是您的实际规则。您可以将allow
规则应用于一种或多种方法。 allow
语句的条件必须评估为 true,Cloud Firestore 或 Cloud Storage 才能授予任何传入请求。您还可以编写不带条件的allow
语句,例如allow read
。但是,如果allow
语句不包含条件,它总是允许对该方法的请求。
如果满足该方法的任何allow
规则,则允许该请求。此外,如果更广泛的规则授予访问权限,则规则授予访问权限并忽略可能限制访问的任何更细化的规则。
考虑以下示例,其中任何用户都可以读取或删除他们自己的任何文件。如果请求写入的用户拥有文件并且文件是 PNG,则更细化的规则仅允许写入。用户可以删除子路径中的任何文件——即使它们不是 PNG——因为之前的规则允许这样做。
service firebase.storage {
// Allow the requestor to read or delete any resource on a path under the
// user directory.
match /users/{userId}/{anyUserFile=**} {
allow read, delete: if request.auth != null && request.auth.uid == userId;
}
// Allow the requestor to create or update their own images.
// When 'request.method' == 'delete' this rule and the one matching
// any path under the user directory would both match and the `delete`
// would be permitted.
match /users/{userId}/images/{imageId} {
// Whether to permit the request depends on the logical OR of all
// matched rules. This means that even if this rule did not explicitly
// allow the 'delete' the earlier rule would have.
allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
}
}
方法
每个allow
语句都包含一个方法,该方法为同一方法的传入请求授予访问权限。
方法 | 请求类型 |
---|---|
便捷方法 | |
read | 任何类型的读取请求 |
write | 任何类型的写请求 |
标准方法 | |
get | 读取单个文档或文件的请求 |
list | 读取查询和集合请求 |
create | 编写新文档或文件 |
update | 写入现有数据库文档或更新文件元数据 |
delete | 删除数据 |
您不能在同一match
块中重叠读取方法,也不能在同一path
声明中重叠写入方法。
例如,以下规则将失败:
service bad.example {
match /rules/with/overlapping/methods {
// This rule allows reads to all authenticated users
allow read: if request.auth != null;
match another/subpath {
// This secondary, more specific read rule causes an error
allow get: if request.auth != null && request.auth.uid == "me";
// Overlapping write methods in the same path cause an error as well
allow write: if request.auth != null;
allow create: if request.auth != null && request.auth.uid == "me";
}
}
}
功能
随着您的安全规则变得越来越复杂,您可能希望将条件集包装在可以在您的规则集中重复使用的函数中。安全规则支持自定义函数。自定义函数的语法有点像 JavaScript,但安全规则函数是用具有一些重要限制的特定领域语言编写的:
- 函数只能包含一个
return
语句。它们不能包含任何附加逻辑。例如,它们不能执行循环或调用外部服务。 - 函数可以从定义它们的范围内自动访问函数和变量。例如,
service cloud.firestore
范围内定义的函数可以访问resource
变量和内置函数,例如get()
和exists()
。 - 函数可以调用其他函数但不能递归。总调用堆栈深度限制为 20。
- 在规则版本
v2
中,函数可以使用let
关键字定义变量。函数最多可以有 10 个 let 绑定,但必须以 return 语句结尾。
函数使用function
关键字定义,并接受零个或多个参数。例如,您可能希望将上面示例中使用的两种类型的条件组合到一个函数中:
service cloud.firestore {
match /databases/{database}/documents {
// True if the user is signed in or the requested data is 'public'
function signedInOrPublic() {
return request.auth.uid != null || resource.data.visibility == 'public';
}
match /cities/{city} {
allow read, write: if signedInOrPublic();
}
match /users/{user} {
allow read, write: if signedInOrPublic();
}
}
}
这是一个显示函数参数和 let 赋值的示例。 let 赋值语句必须用分号分隔。
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
return isAuthor || isAdmin;
}
请注意isAdmin
分配如何强制查找管理员集合。对于不需要不需要的查找的懒惰评估,利用&&
(AND) 和||
的短路特性(或)仅当isAuthor
显示为真(对于&&
比较)或假(对于||
比较)时才调用第二个函数的比较。
function isAdmin(userId) {
return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
// `||` is short-circuiting; isAdmin called only if isAuthor == false.
return isAuthor || isAdmin(userId);
}
随着规则复杂性的增加,在安全规则中使用函数可以使它们更易于维护。
实时数据库
如上所述,实时数据库规则包括三个基本元素:作为数据库 JSON 结构镜像的数据库位置、请求类型和授予访问权限的条件。
数据库位置
您的规则结构应遵循您存储在数据库中的数据结构。例如,在带有消息列表的聊天应用程序中,您可能拥有如下所示的数据:
{
"messages": {
"message0": {
"content": "Hello",
"timestamp": 1405704370369
},
"message1": {
"content": "Goodbye",
"timestamp": 1405704395231
},
...
}
}
您的规则应该反映该结构。例如:
{
"rules": {
"messages": {
"$message": {
// only messages from the last ten minutes can be read
".read": "data.child('timestamp').val() > (now - 600000)",
// new messages must have a string content and a number timestamp
".validate": "newData.hasChildren(['content', 'timestamp']) &&
newData.child('content').isString() &&
newData.child('timestamp').isNumber()"
}
}
}
}
如上例所示,实时数据库规则支持$location
变量来匹配路径段。在你的路径段前面使用$
前缀来匹配你的规则到路径上的任何子节点。
{
"rules": {
"rooms": {
// This rule applies to any child of /rooms/, the key for each room id
// is stored inside $room_id variable for reference
"$room_id": {
"topic": {
// The room's topic can be changed if the room id has "public" in it
".write": "$room_id.contains('public')"
}
}
}
}
}
您还可以将$variable
与常量路径名并行使用。
{
"rules": {
"widget": {
// a widget can have a title or color attribute
"title": { ".validate": true },
"color": { ".validate": true },
// but no other child paths are allowed
// in this case, $other means any key excluding "title" and "color"
"$other": { ".validate": false }
}
}
}
方法
在实时数据库中,存在三种类型的规则。其中两种规则类型—— read
和write
——适用于传入请求的方法。 validate
规则类型强制执行数据结构并验证数据的格式和内容。规则在验证.write
规则授予访问权限后运行.validate
规则。
规则类型 | |
---|---|
。读 | 描述是否以及何时允许用户读取数据。 |
。写 | 描述是否以及何时允许写入数据。 |
。证实 | 定义格式正确的值的外观、它是否具有子属性以及数据类型。 |
默认情况下,如果没有规则允许,则拒绝访问路径。
建筑条件
云端 Firestore
条件是一个布尔表达式,用于确定是允许还是拒绝特定操作。 request
和resource
变量为这些条件提供上下文。
request
变量
request
变量包含以下字段及对应信息:
request.auth
包含来自 Firebase 身份验证的身份验证凭据的 JSON Web 令牌 (JWT)。 auth
令牌包含一组标准声明和您通过 Firebase 身份验证创建的任何自定义声明。详细了解Firebase 安全规则和身份验证。
request.method
request.method
可以是任何标准方法或自定义方法。还存在便利方法read
和write
以简化分别适用于所有只读或所有只写标准方法的写入规则。
request.params
request.params
包括任何与request.resource
无关但可能对评估有用的数据。实际上,对于所有标准方法,这个映射应该是空的,并且应该包含自定义方法的非资源数据。服务必须注意不要重命名或修改作为参数显示的任何键和值的类型。
request.path
request.path
是目标resource
的路径。路径是相对于服务的。包含非 url 安全字符(例如/
)的路径段是 url 编码的。
resource
变量
resource
是服务中的当前值,表示为键值对映射。在条件中引用resource
将导致最多从服务中读取一次值。此查找将计入资源的任何与服务相关的配额。对于get
请求, resource
将仅计入拒绝时的配额。
运算符和运算符优先级
使用下表作为运算符及其在 Cloud Firestore 和 Cloud Storage 规则中的相应优先级的参考。
给定任意表达式a
和b
、一个字段f
和一个索引i
。
操作员 | 描述 | 结合性 |
---|---|---|
a[i] a() af | 索引、调用、字段访问 | 左到右 | !a -a | 一元否定 | 右到左 |
a/ba%ba*b | 乘法运算符 | 左到右 |
a+b ab | 加法运算符 | 左到右 |
a>ba>=ba | 关系运算符 | 左到右 |
a in b | 存在于列表或地图中 | 左到右 |
a is type | 类型比较,其中type 可以是 bool、int、float、number、string、list、map、timestamp、duration、path 或 latlng | 左到右 |
a==ba!=b | 比较运算符 | 左到右 | a && b | 条件与 | 左到右 |
a || b | 条件或 | 左到右 |
a ? true_value : false_value | 三元表达式 | 左到右 |
云储存
条件是一个布尔表达式,用于确定是允许还是拒绝特定操作。 request
和resource
变量为这些条件提供上下文。
request
变量
request
变量包含以下字段及对应信息:
request.auth
包含来自 Firebase 身份验证的身份验证凭据的 JSON Web 令牌 (JWT)。 auth
令牌包含一组标准声明和您通过 Firebase 身份验证创建的任何自定义声明。详细了解Firebase 安全规则和身份验证。
request.method
request.method
可以是任何标准方法或自定义方法。还存在便利方法read
和write
以简化分别适用于所有只读或所有只写标准方法的写入规则。
request.params
request.params
包括任何与request.resource
无关但可能对评估有用的数据。实际上,对于所有标准方法,这个映射应该是空的,并且应该包含自定义方法的非资源数据。服务必须注意不要重命名或修改作为参数显示的任何键和值的类型。
request.path
request.path
是目标resource
的路径。路径是相对于服务的。包含非 url 安全字符(例如/
)的路径段是 url 编码的。
resource
变量
resource
是服务中的当前值,表示为键值对映射。在条件中引用resource
将导致最多从服务中读取一次值。此查找将计入资源的任何与服务相关的配额。对于get
请求, resource
将仅计入拒绝时的配额。
运算符和运算符优先级
使用下表作为运算符及其在 Cloud Firestore 和 Cloud Storage 规则中的相应优先级的参考。
给定任意表达式a
和b
、一个字段f
和一个索引i
。
操作员 | 描述 | 结合性 |
---|---|---|
a[i] a() af | 索引、调用、字段访问 | 左到右 | !a -a | 一元否定 | 右到左 |
a/ba%ba*b | 乘法运算符 | 左到右 |
a+b ab | 加法运算符 | 左到右 |
a>ba>=ba | 关系运算符 | 左到右 |
a in b | 存在于列表或地图中 | 左到右 |
a is type | 类型比较,其中type 可以是 bool、int、float、number、string、list、map、timestamp、duration、path 或 latlng | 左到右 |
a==ba!=b | 比较运算符 | 左到右 | a && b | 条件与 | 左到右 |
a || b | 条件或 | 左到右 |
a ? true_value : false_value | 三元表达式 | 左到右 |
实时数据库
条件是一个布尔表达式,用于确定是允许还是拒绝特定操作。您可以通过以下方式在实时数据库规则中定义这些条件。
预定义变量
有许多有用的预定义变量可以在规则定义中访问。以下是每个的简要总结:
预定义变量 | |
---|---|
现在 | 自 Linux 纪元以来的当前时间(以毫秒为单位)。这特别适用于验证使用 SDK 的 firebase.database.ServerValue.TIMESTAMP 创建的时间戳。 |
根 | 一个RuleDataSnapshot ,表示在尝试操作之前 Firebase 数据库中的根路径。 |
新数据 | 一个RuleDataSnapshot ,表示在尝试操作后将存在的数据。它包括正在写入的新数据和现有数据。 |
数据 | 一个RuleDataSnapshot ,表示在尝试操作之前存在的数据。 |
$变量 | 用于表示 ID 和动态子键的通配符路径。 |
授权 | 表示经过身份验证的用户的令牌负载。 |
这些变量可以在您的规则中的任何地方使用。例如,下面的安全规则确保写入/foo/
节点的数据必须是小于 100 个字符的字符串:
{ "rules": { "foo": { // /foo is readable by the world ".read": true, // /foo is writable by the world ".write": true, // data written to /foo must be a string less than 100 characters ".validate": "newData.isString() && newData.val().length < 100" } } }
基于数据的规则
您数据库中的任何数据都可以在您的规则中使用。使用预定义变量root
、 data
和newData
,您可以访问写入事件之前或之后存在的任何路径。
考虑这个例子,它允许写操作,只要/allow_writes/
节点的值为true
,父节点没有设置readOnly
标志,并且在新写入的数据中有一个名为foo
的子节点:
".write": "root.child('allow_writes').val() === true && !data.parent().child('readOnly').exists() && newData.child('foo').exists()"
基于查询的规则
虽然您不能将规则用作过滤器,但您可以通过在规则中使用查询参数来限制对数据子集的访问。使用query.
规则中的表达式以根据查询参数授予读取或写入访问权限。
例如,以下基于查询的规则使用基于用户的安全规则和基于查询的规则将对购物baskets
集合中数据的访问限制为仅活动用户拥有的购物篮:
"baskets": {
".read": "auth.uid !== null &&
query.orderByChild === 'owner' &&
query.equalTo === auth.uid" // restrict basket access to owner of basket
}
以下查询(包括规则中的查询参数)将会成功:
db.ref("baskets").orderByChild("owner")
.equalTo(auth.currentUser.uid)
.on("value", cb) // Would succeed
但是,不包含规则中参数的查询将失败并出现PermissionDenied
错误:
db.ref("baskets").on("value", cb) // Would fail with PermissionDenied
您还可以使用基于查询的规则来限制客户端通过读取操作下载的数据量。
例如,以下规则将读取访问权限限制为仅按优先级排序的查询的前 1000 个结果:
messages: {
".read": "query.orderByKey &&
query.limitToFirst <= 1000"
}
// Example queries:
db.ref("messages").on("value", cb) // Would fail with PermissionDenied
db.ref("messages").limitToFirst(1000)
.on("value", cb) // Would succeed (default order by key)
以下query.
表达式在实时数据库规则中可用。
基于查询的规则表达式 | ||
---|---|---|
表达 | 类型 | 描述 |
查询.orderByKey 查询.orderByPriority 查询.orderByValue | 布尔值 | 对于按键、优先级或值排序的查询为真。否则为假。 |
query.orderByChild | 细绳 无效的 | 使用字符串表示子节点的相对路径。例如, query.orderByChild === "address/zip" 。如果查询未按子节点排序,则此值为空。 |
查询.startAt 查询.endAt 查询.等于 | 细绳 数字 布尔值 无效的 | 检索执行查询的边界,如果没有边界集则返回 null。 |
查询.limitToFirst 查询.limitToLast | 数字 无效的 | 检索执行查询的限制,如果未设置限制,则返回 null。 |
运营商
实时数据库规则支持许多运算符,您可以使用这些运算符在条件语句中组合变量。请参阅参考文档中的完整运算符列表。
创造条件
您的实际情况将根据您要授予的访问权限而有所不同。规则有意提供了极大程度的灵活性,因此您的应用程序的规则最终可以根据您的需要变得简单或复杂。
有关创建简单的生产就绪规则的一些指南,请参阅基本安全规则。