Firebase 安全规则利用灵活、强大的自定义语言,可以支持各种复杂情况和精细化方面的安全需求。您可以按照应用的具体需要,设置特定的规则或者一般性的规则。Realtime Database 规则使用的语法类似 JSON 格式的 JavaScript。Cloud Firestore 和 Cloud Storage 规则使用一种基于通用表达式语言 (CEL) 的语言进行构建,并使用 match
和 allow
语句来支持有条件地授予访问权限。
但是,由于这些是自定义语言,因此需要一些时间来学习。在您深入了解更复杂的规则时,阅读本指南有助于您更好地了解此规则语言。
选择一种产品以详细了解其规则。
基本结构
Cloud 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>>
}
}
在您构建规则时,请务必了解以下主要概念:
- 请求:
allow
语句中调用的一种或多种方法。这些是您获准运行的方法。标准方法包括get
、list
、create
、update
和delete
。read
和write
简便方法会启用对指定的数据库或存储路径的广泛读写权限。 - 路径:数据库或存储位置,表示为 URI 路径。
- 规则:
allow
语句,如果其中所含条件的计算结果为 true,则允许请求。
下文会进一步详细描述以上每个概念。
Cloud Storage
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>>
}
}
在您构建规则时,请务必了解以下主要概念:
- 请求:
allow
语句中调用的一种或多种方法。这些是您获准运行的方法。标准方法包括get
、list
、create
、update
和delete
。read
和write
简便方法会启用对指定的数据库或存储路径的广泛读写权限。 - 路径:数据库或存储位置,表示为 URI 路径。
- 规则:
allow
语句,如果其中所含条件的计算结果为 true,则允许请求。
下文会进一步详细描述以上每个概念。
Realtime Database
在 Realtime Database 中,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
规则充当辅助验证,以根据传入或现有数据授予访问权限。 - 条件:如果条件的计算结果为 true,则会允许请求。
规则构造
Cloud Firestore
Cloud Firestore 和 Cloud Storage 中规则的基本元素如下所示:
service
声明:声明规则适用的 Firebase 产品。match
代码块:定义规则适用的数据库或存储桶中的路径。allow
语句:提供授予访问权限的条件,按方法进行区分。支持的方法包括:get
、list
、create
、update
、delete
以及简便方法read
和write
。- 可选的
function
声明:可让您组合和封装多项条件以便跨多个规则使用。
service
包含一个或多个 match
代码块,代码块通过 allow
语句提供为请求授予访问权限的条件。规则条件中可使用 request
和 resource
变量。Firebase 安全规则语言还支持 function
声明。
语法版本
syntax
语句指示用于编写源代码的 Firebase 规则语言的版本。该语言的最新版本为 v2
。
rules_version = '2';
service cloud.firestore {
...
}
如果未提供 rules_version
语句,系统将使用 v1
引擎评估您的规则。
Service
service
声明定义了您的规则适用于哪些 Firebase 产品或服务。每个源文件只能包含一个 service
声明。
Cloud Firestore
service cloud.firestore {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
Cloud Storage
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
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}
。此变量可作为string
在match
语句中访问。 - 递归通配符:递归或多段通配符匹配路径中或其子路径中的多个路径段。此通配符匹配您设置它的位置以下层级中的所有路径。您可以通过在段变量的末尾添加
=**
字符串来声明此变量:{variable=**}
。此变量可作为path
对象在match
语句中访问。
Allow
match
代码块包含一个或多个 allow
语句。这些是您的实际规则。您可以将 allow
规则应用于一个或多个方法。对于 Cloud Firestore 或 Cloud Storage,一个 allow
语句中的条件必须评估为 true,才能允许传入的请求。您也可以编写 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
分配如何强制查找管理员集合。如需在免除不必要查找的情况下进行惰性求值,请充分利用 &&
(与)和 ||
(或)比较运算符的短路机制,仅在 isAuthor
显示为 true(针对 &&
比较运算符)或 false(针对 ||
比较运算符)时才调用第二个函数。
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 Storage
Cloud Firestore 和 Cloud Storage 中规则的基本元素如下所示:
service
声明:声明规则适用的 Firebase 产品。match
代码块:定义规则适用的数据库或存储桶中的路径。allow
语句:提供授予访问权限的条件,按方法进行区分。支持的方法包括:get
、list
、create
、update
、delete
以及简便方法read
和write
。- 可选的
function
声明:可让您组合和封装多项条件以便跨多个规则使用。
service
包含一个或多个 match
代码块,代码块通过 allow
语句提供为请求授予访问权限的条件。规则条件中可使用 request
和 resource
变量。Firebase 安全规则语言还支持 function
声明。
语法版本
syntax
语句指示用于编写源代码的 Firebase 规则语言的版本。该语言的最新版本为 v2
。
rules_version = '2';
service cloud.firestore {
...
}
如果未提供 rules_version
语句,系统将使用 v1
引擎评估您的规则。
Service
service
声明定义了您的规则适用于哪些 Firebase 产品或服务。每个源文件只能包含一个 service
声明。
Cloud Firestore
service cloud.firestore {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
Cloud Storage
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
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}
。此变量可作为string
在match
语句中访问。 - 递归通配符:递归或多段通配符匹配路径中或其子路径中的多个路径段。此通配符匹配您设置它的位置以下层级中的所有路径。您可以通过在段变量的末尾添加
=**
字符串来声明此变量:{variable=**}
。此变量可作为path
对象在match
语句中访问。
Allow
match
代码块包含一个或多个 allow
语句。这些是您的实际规则。您可以将 allow
规则应用于一个或多个方法。对于 Cloud Firestore 或 Cloud Storage,一个 allow
语句中的条件必须评估为 true,才能允许传入的请求。您也可以编写 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
分配如何强制查找管理员集合。如需在免除不必要查找的情况下进行惰性求值,请充分利用 &&
(与)和 ||
(或)比较运算符的短路机制,仅在 isAuthor
显示为 true(针对 &&
比较运算符)或 false(针对 ||
比较运算符)时才调用第二个函数。
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);
}
在安全规则中使用函数可以在规则变得越来越复杂时使其更易于维护。
Realtime Database
如上所述,Realtime Database 规则包括三个基本元素:作为数据库的 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()"
}
}
}
}
如上例所示,Realtime Database 规则支持使用 $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 }
}
}
}
方法
在 Realtime Database 中,有三种类型的规则。其中两种规则类型(read
和 write
)适用于传入请求的方法。validate
规则类型强制执行数据结构并验证数据的格式和内容。规则在验证 .write
规则授予访问权限之后运行 .validate
规则。
规则类型 | |
---|---|
.read | 描述是否以及何时允许用户读取数据。 |
.write | 描述是否以及何时允许写入数据。 |
.validate | 定义值的正确格式、值是否包含子属性以及值的数据类型。 |
默认情况下,如果没有允许它的规则,则拒绝在路径上进行访问。
构建条件
Cloud Firestore
条件是一个布尔表达式,用于确定应该允许还是拒绝执行特定操作。request
和 resource
变量为这些条件提供上下文。
request
变量
request
变量包括以下字段和相应的信息:
request.auth
一个 JSON Web 令牌 (JWT),包含 Firebase Authentication 提供的身份验证凭据。auth
令牌包含一组标准声明以及您通过 Firebase Authentication 创建的所有自定义声明。详细了解 Firebase 安全规则和身份验证。
request.method
request.method
可以是任一标准方法或一种自定义方法。也存在简便方法 read
和 write
,可以简化分别适用于全部只读或全部只写标准方法的编写规则。
request.params
request.params
包括与 request.resource
无关的所有数据,这些数据可能对求值有用。实际上,此映射对于所有标准方法应为空,对自定义方法应包含非资源数据。服务定义必须仔细,不要重命名或修改任何作为参数的键和值的类型。
request.path
request.path
是目标 resource
的路径。此路径相对于服务路径。包含非网址安全字符(例如 /
)的路径段采用网址编码形式。
resource
变量
resource
是服务中的当前值,表示为键值对的映射。在条件内引用 resource
将导致最多一次从服务中读取该值。此查询将计入资源的所有与服务相关的配额。对于 get
请求,resource
将仅在拒绝时计入配额。
运算符和运算符优先级
使用下表作为 Cloud Firestore 和 Cloud Storage 规则中的运算符及其相应优先级的参考。
给定任意表达式 a
和 b
、字段 f
和索引 i
。
运算符 | 说明 | 关联度 |
---|---|---|
a[i] a() a.f |
索引、调用、字段访问 | 从左到右 |
!a -a |
一元否定 | 从右到左 |
a/b a%b a*b |
乘法运算符 | 从左到右 |
a+b a-b |
加法运算符 | 从左到右 |
a>b a>=b a<=b |
关系运算符 | 从左到右 |
a in b |
存在于列表或映射中 | 从左到右 |
a is type |
类型比较,其中 type 可以是 bool、int、float、number、string、list、map、timestamp、duration、path 或 latlng |
从左到右 |
a==b a!=b |
比较运算符 | 从左到右 |
a && b |
条件“与” | 从左到右 |
a || b |
条件“或” | 从左到右 |
a ? true_value : false_value |
三元表达式 | 从左到右 |
Cloud Storage
条件是一个布尔表达式,用于确定应该允许还是拒绝执行特定操作。request
和 resource
变量为这些条件提供上下文。
request
变量
request
变量包括以下字段和相应的信息:
request.auth
一个 JSON Web 令牌 (JWT),包含 Firebase Authentication 提供的身份验证凭据。auth
令牌包含一组标准声明以及您通过 Firebase Authentication 创建的所有自定义声明。详细了解 Firebase 安全规则和身份验证。
request.method
request.method
可以是任一标准方法或一种自定义方法。也存在简便方法 read
和 write
,可以简化分别适用于全部只读或全部只写标准方法的编写规则。
request.params
request.params
包括与 request.resource
无关的所有数据,这些数据可能对求值有用。实际上,此映射对于所有标准方法应为空,对自定义方法应包含非资源数据。服务定义必须仔细,不要重命名或修改任何作为参数的键和值的类型。
request.path
request.path
是目标 resource
的路径。此路径相对于服务路径。包含非网址安全字符(例如 /
)的路径段采用网址编码形式。
resource
变量
resource
是服务中的当前值,表示为键值对的映射。在条件内引用 resource
将导致最多一次从服务中读取该值。此查询将计入资源的所有与服务相关的配额。对于 get
请求,resource
将仅在拒绝时计入配额。
运算符和运算符优先级
使用下表作为 Cloud Firestore 和 Cloud Storage 规则中的运算符及其相应优先级的参考。
给定任意表达式 a
和 b
、字段 f
和索引 i
。
运算符 | 说明 | 关联度 |
---|---|---|
a[i] a() a.f |
索引、调用、字段访问 | 从左到右 |
!a -a |
一元否定 | 从右到左 |
a/b a%b a*b |
乘法运算符 | 从左到右 |
a+b a-b |
加法运算符 | 从左到右 |
a>b a>=b a<=b |
关系运算符 | 从左到右 |
a in b |
存在于列表或映射中 | 从左到右 |
a is type |
类型比较,其中 type 可以是 bool、int、float、number、string、list、map、timestamp、duration、path 或 latlng |
从左到右 |
a==b a!=b |
比较运算符 | 从左到右 |
a && b |
条件“与” | 从左到右 |
a || b |
条件“或” | 从左到右 |
a ? true_value : false_value |
三元表达式 | 从左到右 |
Realtime Database
条件是一个布尔表达式,用于确定应该允许还是拒绝执行特定操作。您可以通过以下方式在 Realtime Database 规则中定义这些条件。
预定义变量
在规则定义中可访问很多有用的预定义变量。下面简要总结了各个变量:
预定义变量 | |
---|---|
now | 当前时间,以从 Linux 计时原点开始计算的毫秒数表示。此变量非常适合验证使用 SDK 的 firebase.database.ServerValue.TIMESTAMP 创建的时间戳。 |
root | RuleDataSnapshot 对象,代表在尝试操作之前存在于 Firebase 数据库中的根路径。 |
newData | RuleDataSnapshot 对象,代表尝试操作完成后应存在的数据。该数据包含写入的新数据和现有数据。 |
data | RuleDataSnapshot 对象,代表在尝试操作之前存在的数据。 |
$ variables | 用于表示 ID 和动态子键的通配符路径。 |
auth | 表示通过身份验证的用户的令牌有效负载。 |
这些变量可用于您的规则的任何位置。例如,以下安全规则可确保写入 /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)
Realtime Database 安全规则中提供以下 query.
表达式。
基于查询的规则表达式 | ||
---|---|---|
表达式 | 类型 | 说明 |
query.orderByKey query.orderByPriority query.orderByValue |
布尔值 | 对于按键、优先级或值排序的查询,为 true。否则为 false。 |
query.orderByChild | 字符串 null |
使用字符串来表示到一个子节点的相对路径。例如,query.orderByChild === "address/zip" 。如果查询并非按子节点排序,则此值为 null。
|
query.startAt query.endAt query.equalTo |
字符串 数字 布尔值 null |
检索正在执行的查询的范围,如果没有设置范围,则返回 null。 |
query.limitToFirst query.limitToLast |
数字 null |
检索对正在执行的查询的限制,如果没有设置限制,则返回 null。 |
运算符
Realtime Databse 规则支持许多运算符,您可以使用这些运算符合并条件语句中的变量。请参阅参考文档中运算符的完整列表。
创建条件
您的实际条件将因您要授予的访问权限而有所不同。 规则有意提供了极大的灵活性,因此您的应用规则最终可以简单或复杂,具体取决于您的需求。
如需在创建支持生产环境的简单规则方面获得一些指导,请参阅基本安全规则。