规则:类型
.read
授予客户端对 Firebase Realtime Database 位置的读取权限。
.read
规则是一种安全规则,可授予客户端对 Firebase Realtime Database 位置的读取权限。例如:
".read": "auth != null && auth.provider == 'twitter'"
.read
规则的值是一个字符串,它被评估为 JavaScript 表达式语法的子集,并进行了几项行为变更,以提高清晰度和正确性。授予读取某个营业地点的权限的 .read
规则也将允许读取该营业地点的任何下级,即使下级拥有自己的 .read
规则失败也是如此。
.read
规则可以访问除 newData
之外的所有 Firebase Realtime Database 规则变量。
.write
授予对 Firebase Realtime Database 位置的客户端写入权限。
.write
规则是一种安全规则,可授予客户端对 Firebase Realtime Database 位置的写入权限。例如:
".write": "auth != null && auth.token.isAdmin == true"
.write
规则的值是一个字符串,它被评估为 JavaScript 表达式语法的子集,并进行了几项行为变更,以提高清晰度和正确性。用于授予写入某个位置的权限的 .write
规则也将允许对该位置的任何下级执行写入操作,即使下级式自身的 .write
规则失败也是如此。
.write
规则可以访问 Firebase Realtime Database 的所有规则变量。
.validate
在 .write
规则授予访问权限后使用,以确保要写入的数据符合特定架构。
在 .write
规则授予访问权限后,系统会使用 .validate
规则来确保写入的数据符合特定标准。除了授予访问权限的 .write
之外,所有相关的 .validate
规则都必须成功执行,然后才能执行写入操作。例如:
".validate": "newData.hasChildren(['name', 'age'])"
.validate
规则的值是一个字符串,它被评估为 JavaScript 表达式语法的子集,并进行了几项行为变更,以提高清晰度和正确性。
.validate
规则可以访问 Firebase Realtime Database 的所有规则变量。
.indexOn
告知 Firebase Realtime Database 您希望将数据编入索引的键,从而提高查询性能。
.indexOn
规则会告知 Firebase Realtime Database 服务器将您数据中的特定键编入索引,以提高查询性能。例如,假设某个数据库中有恐龙数据集合,我们可以通过添加此规则来指示 Firebase Realtime Database 在查询从服务器返回之前针对查询进行优化:
{
"rules": {
"dinosaurs": {
".indexOn": ["height", "length"]
}
}
}
如需详细了解 .indexOn
规则,请参阅安全指南中关于将数据编入索引的部分。
规则:变量
auth
包含令牌载荷的变量(如果客户端已通过身份验证)或 null
如果客户端未通过身份验证,则会发生此错误。
Firebase Realtime Database 让您可以轻松向多个内置提供程序进行身份验证,并为它们生成身份验证令牌。用户使用某个内置提供程序进行身份验证后,auth 变量将包含以下内容:
字段 | 说明 |
---|---|
provider |
所用的身份验证方法(例如“password”“anonymous”“facebook”“github”“google”或“twitter”)。 |
uid |
唯一用户 ID,保证在所有提供程序中都是唯一的。 |
token |
Firebase Auth ID 令牌的内容。请参阅 auth.token 。 |
举个例子,我们可以设置如下规则,允许用户创建评论,只要用户将他们的用户 ID 与评论存储在一起即可:
{
"rules": {
".read": true,
"$comment": {
".write": "!data.exists() && newData.child('user_id').val() == auth.uid"
}
}
}
我们还可以创建如下规则,允许通过 Facebook 登录的用户创建评论:
{
"rules": {
".read": true,
"$comment": {
".write": "!data.exists() && auth.provider == 'facebook'"
}
}
}
auth.token 。
包含 Firebase Auth ID 令牌内容的变量。
该令牌包含以下部分或全部键:
字段 | 说明 |
---|---|
email |
与账号关联的电子邮件地址(如果存在)。 |
email_verified |
如果用户已验证他们可以访问 email 地址,则为 true 。某些提供方会自动验证他们拥有的电子邮件地址。 |
phone_number |
与账号关联的电话号码(如果有)。 |
name |
用户的显示名(如果已设置)。 |
sub |
用户的 Firebase UID。此 UID 在项目中是唯一的。 |
firebase.identities |
与此用户账号关联的所有身份的字典。字典的键可以是以下任一值:email 、phone 、google.com 、facebook.com 、github.com 、twitter.com 。字典的值是与账号关联的每个身份提供方的唯一标识符的数组。例如,auth.token.firebase.identities["google.com"][0] 包含与该账号关联的第一个 Google 用户 ID。 |
firebase.sign_in_provider |
用于获取此令牌的登录服务提供方。可以是以下任一字符串:custom 、password 、phone 、anonymous 、google.com 、facebook.com 、github.com 、twitter.com 。 |
firebase.tenant |
与账号关联的租户 ID(如有)。例如 tenant2-m6tyz |
如果使用自定义身份验证,auth.token
还包含任何自定义
声明。
所有这些值都可以在规则中使用。例如,要限制对与 gmail.com 地址关联的 Google 账号的访问权限,我们可以添加以下规则:
{
"rules": {
".read": "auth != null",
"gmailUsers": {
"$uid": {
".write": "auth.token.email_verified == true && auth.token.email.matches(/.*@gmail.com$/)"
}
}
}
}
为完整起见,auth.token
中也加入了以下字段,但它们对规则可能没什么用。
字段 | 说明 |
---|---|
iss |
令牌的颁发者。 |
aud |
令牌的目标设备。 |
auth_time |
用户上次使用接收令牌的设备使用凭据进行身份验证的时间。 |
iat |
令牌的颁发时间。 |
exp |
令牌的过期时间。 |
$location
一个变量,可用于引用之前在规则结构中使用的 $location
的键。
如果您的规则结构中有 $location
,您可以在规则表达式中使用匹配的 $
变量来获取被读取或写入的实际子级的名称。因此,假设我们希望向每位用户授予对其 /users/<user>
位置的读写权限。我们可以使用:
{
"rules": {
"users": {
"$user": {
".read": "auth.uid === $user",
".write": "auth.uid === $user"
}
}
}
}
当客户端尝试访问 /users/barney
时,$user
默认位置将与等于“barney”的 $user
匹配。因此,.read
规则将检查 auth.uid === 'barney'
。因此,只有在使用“barney” uid 对客户端进行身份验证时,读取
才会成功。/users/barney
现在
包含根据 Firebase Realtime Database 服务器自 Unix 纪元起经过的毫秒数。
now
变量包含从 UNIX 纪元开始计算的毫秒数(根据 Firebase Realtime Database 服务器计算)。例如,您可以使用此字段来验证用户的 created
时间从未设置为将来的时间:
{
"rules": {
"users": {
"$user": {
"created": {
".validate": "newData.val() < now"
}
}
}
}
}
root
与 Firebase Realtime Database 根目录下的当前数据对应的 RuleDataSnapshot。
根变量为您提供与 Firebase Realtime Database 根目录下的当前数据相对应的 RuleDataSnapshot。可以使用它通过规则表达式读取数据库中的任何数据。例如,如果我们希望仅在用户的 /users/<id>/active
设置为 true 时才允许用户读取 /comments
,则可以使用以下代码:
{
"rules": {
"comments": {
".read": "root.child('users').child(auth.uid).child('active').val() == true"
}
}
}
然后,如果 /users/barney/active
包含值 true,则用户使用“barney” UID 对用户进行身份验证可以写入 /comments
节点。
数据
一个 RuleDataSnapshot,对应 Firebase Realtime Database 中当前正在执行的规则所在位置的数据。
数据变量为您提供 RuleDataSnapshot,与当前正在执行的规则的数据库位置中的当前数据相对应(与 root 相反,根相反, root 可返回数据库根的数据)。
例如,如果您想在 /users/<user>/public
设置为 true 时允许任何客户端访问 /users/<user>
,则可以使用以下代码:
{
"rules": {
"users": {
"$user": {
".read": "data.child('public').val() == true"
}
}
}
}
数据变量在 .read
、.write
和
.validate
条规则。
newData
与允许写入时产生的数据对应的 RuleDataSnapshot。
对于 .write
和 .validate
规则,newData 变量会为您提供 RuleDataSnapshot,对应于允许写入时产生的数据(这是现有数据与正在写入的新数据的“合并”)。因此,如果您想确保每位用户都有姓名和年龄,可以使用:
{
"rules": {
"users": {
"$user": {
".read": true,
".write": true,
".validate": "newData.hasChildren(['name', 'age'])"
}
}
}
}
由于 newData 合并现有数据和新数据,因此即使是“部分”数据,它也能正常运行。更新。例如:
var fredRef = firebase.database().ref("users/fred");
// Valid since we have a name and age.
fredRef.set({ name: "Fred", age: 19 });
// Valid since we are updating the name but there's already an age.
fredRef.child("age").set(27);
// Invalid since the .validate rule will no longer be true.
fredRef.child("name").remove();
此 newData 变量在 .read
规则中不可用,因为没有写入新数据。您只能使用 data。
RuleDataSnapshot:方法
(
从此 RuleDataSnapshot 中获取原始值(string
、number
、boolean
或 null
)。
返回值:(String
、Number
、Boolean
、Null
) - 此 RuleDataSnapshot 中的原始值。
与 DataSnapshot.val()
不同,对具有子项数据的 RuleDataSnapshot 调用 val()
不会返回包含子项的对象。而是返回一个特殊的标记值。这可确保规则始终能非常高效地执行。
因此,您必须始终使用 child()
访问子项(例如,data.child('name').val()
,而不是 data.val().name
)。
此示例仅当所读取位置的 isReadable 子项设置为 true 时,才允许进行读取。
".read": "data.child('isReadable').val() == true"
child()
获取指定相对路径中位置的 RuleDataSnapshot。
参数:childPath
String
- 子数据所在位置的相对路径。
返回值:RuleDataSnapshot
- 子位置的 RuleDataSnapshot。
相对路径可以是简单的子名称(例如“fred”),也可以是以斜杠分隔的路径(例如“fred/name/first”)。如果子位置没有任何数据,则返回空的 RuleDataSnapshot。
此示例仅当所读取位置的 isReadable 子项设置为 true 时,才允许进行读取。
".read": "data.child('isReadable').val() == true"
parent()
获取父位置的 RuleDataSnapshot。
返回值:RuleDataSnapshot
- 父级位置的 RuleDataSnapshot。
如果此实例引用了 Firebase Realtime Database 的根,则它没有父项,并且 parent()
将失败,导致当前规则表达式被跳过(作为失败)。
此示例只允许在 isReadable 同级项设置为 true 时进行读取。
".read": "data.parent().child('isReadable').val() == true"
hasChild(childPath)
如果指定的子元素存在,则返回 true。
参数:childPath
String
- 潜在子项位置的相对路径。
返回值:Boolean - true
(如果指定子路径中存在数据);其他 false
。
此示例仅允许在数据包含子项“name”时写入数据。
".validate": "newData.hasChild('name')"
hasChildren([children])
检查是否存在子项。
参数:children
Array
可选 - 必须全部存在的子键数组。
返回值:Boolean
- true
(如果指定)子项存在;否则 false
。
如果未提供任何参数,则当 RuleDataSnapshot 有任何子项时,它将返回 true。如果提供了子名称数组,则只有当所有指定的子项都存在于 RuleDataSnapshot 中时,该数组才会返回 true。
本示例仅允许在包含一个或多个子节点的数据时写入数据。
".validate": "newData.hasChildren()"
此示例仅允许写入包含“name”的数据和“age”子女。
".validate": "newData.hasChildren(['name', 'age'])"
已存在()
如果此 RuleDataSnapshot 包含任何数据,则返回 true。
返回值:Boolean
- true
(如果 RuleDataSnapshot 包含任何数据);其他为 false
。
如果此 RuleDataSnapshot 包含任何数据,则现有的函数返回 true。这是一个纯粹的便捷函数,因为 data.exists()
等同于 data.val() != null
。
此示例允许在此位置执行写入操作,前提是没有现有数据。
".write": "!data.exists()"
getPriority()
获取 RuleDataSnapshot 中数据的优先级。
返回值:(String
、Number
、Null
)- 此 RuleDataSnapshot 中数据的优先级。
此示例可确保正在写入的新数据的优先级
".validate": "newData.getPriority() != null"
isNumber()
如果此 RuleDataSnapshot 包含数值,则返回 true。
返回值:Boolean
- true
(如果数据为数字);否则 false
。
此示例可确保正在写入的新数据具有子项“age”以及一个数值。
".validate": "newData.child('age').isNumber()"
isString()
如果此 RuleDataSnapshot 包含字符串值,则返回 true。
返回值:Boolean
- true
(如果数据为 String
);其他 false
。
此示例确保正在写入的新数据具有子项“name”以及一个字符串值。
".validate": "newData.child('name').isString()
isBoolean()
如果此 RuleDataSnapshot 包含布尔值,则返回 true。
返回值:Boolean
- true
(如果数据为 Boolean
);否则 false
。
此示例可确保正在写入的新数据具有“活动”子项以及布尔值。
".validate": "newData.child('active').isBoolean()"
字符串:属性
长度
返回字符串的长度。
返回值:Number
- 字符串中的字符数。
此示例要求字符串至少包含 10 个字符。
".validate": "newData.isString() && newData.val().length >= 10"
字符串:方法
包含(子字符串)
如果字符串包含指定的子字符串,则返回 true。
参数:substring
String
- 要查找的子字符串。
返回值:Boolean
- true
(如果该字符串包含指定的子字符串);否则 false
。
此示例要求数据必须是包含“@”的字符串。
".validate": "newData.isString() && newData.val().contains('@')"
StartWith(子字符串)
如果字符串以指定子字符串开头,则返回 true。
参数:substring
String
- 要在开头查找的子字符串。
返回值:Boolean
- true
(如果该字符串包含指定的子字符串);否则 false
。
此示例允许在 auth.token.identifier
以“internal-”开头时授予读取权限
".read": "auth.token.identifier.beginsWith('internal-')"
EndWith(子字符串)
如果字符串以指定子字符串结尾,则返回 true。
参数:substring
String
- 要在末尾查找的子字符串。
返回值:Boolean
- true
(如果该字符串以指定子字符串结尾);否则 false
。
此示例允许对以“@company.com”结尾的 auth.token.identifier
拥有读取权限
".read": "auth.token.identifier.endsWith('@company.com')"
替换为(子字符串,替换)
返回字符串的副本,并将指定子字符串的所有实例替换为指定的替换字符串。
参数:substring String
- 要查找的子字符串。
replacement String
- 用于替换子字符串的字符串。
返回值:String
- 用替换项替换子字符串后的新字符串。
replace()
方法与 JavaScript replace()
方法略有不同,因为它会将指定子字符串的所有实例替换为指定的替换字符串,而不仅仅是第一个实例。
由于键中不允许使用句点,因此我们需要先使用句点转义字符串,然后再存储字符串。电子邮件地址便是一个这样的例子。假设我们的 /whitelist/
节点中有一个已列入白名单的电子邮件地址列表:
{
"user": {
"$uid": {
"email": <email>
}
},
"whitelist": {
"fred@gmail%2Ecom": true,
"barney@aol%2Ecom": true
}
}
我们可以制定一条规则,仅允许用户加入其电子邮件地址在 /whitelist/
节点中的情况:
{
"rules": {
"users": {
"$uid": {
".read": "true",
".write": "root.child('whitelist').child(newData.child('email').val().replace('.', '%2E')).exists()"
}
}
}
}
toLowerCase()
返回转换为小写的字符串的副本。
返回值:String
- 转换为小写的字符串。
如果 auth.token.identifier
下存在所有小写字符,则此示例允许读取权限。/users
".read": "root.child('users').child(auth.token.identifier.toLowerCase()).exists()"
toUpperCase()
返回转换为大写的字符串的副本。
返回值:String
- 转换为大写的字符串。
此示例允许 auth.token.identifier
进行读取访问,因为 /users
下全部大写。
".read": "root.child('users').child(auth.token.identifier.toUpperCase()).exists()"
匹配(正则表达式)
如果字符串与指定的正则表达式字面量匹配,则返回 true。
返回值:Boolean
- 如果字符串与正则表达式字面量 regex 匹配,则为 true
;否则 false
。
查看完整的规则正则表达式文档。
运算符
+(添加)
用于添加变量或字符串串联。
以下示例可以确保新值将现有值正好增加 1。这对于实现计数器非常有用:
".write": "newData.val() === data.val() + 1"
".validate": "root.child('room_names/' + $room_id).exists()"
-(否定或减)
用于否定规则表达式中的一个值或减去两个值。
此验证规则检查新值是否为该位置处的子值的反函数:
".validate": "newData.val() === -(data.child('quantity').val())"
以下示例使用减法来确保只能读取过去十分钟内的消息:
".read": "newData.child('timestamp').val() > (now - 600000)"
*(乘号)
用于相乘规则表达式中的变量。
此验证规则会检查新值是否与价格和数量(两个现有值)的产物相等:
".validate": "newData.val() === data.child('price').val() * data.child('quantity').val()"
/(除号)
用于划分规则表达式中的变量。
在以下示例中,验证规则会确保存储的数据是存储在其他位置的总数据的平均值:
".validate": "newData.val() === data.parent().child('sum').val() / data.parent().child('numItems').val()"
%(模数)
用于查找规则表达式中一个变量除以另一个变量的余数。
此规则用于验证是否只能写入偶数:
".validate": "newData.val() % 2 === 0"
===(等于)
用于检查规则表达式中的两个变量是否具有相同的类型和值。
以下规则使用 === 运算符,仅向用户账号的所有者授予写入权限。用户的 uid 必须与键 ($user_id
) 完全匹配,才能使规则评估为 true。
"users": {
".write": "$user_id === auth.uid"
}
!==(不等于)
用于检查规则表达式中两个变量是否不相等。
以下读取规则可确保只有已登录的用户才能读取数据:
".read": "auth !== null"
&&(且)
如果两个操作数都为 true,则求值结果为 true。用于对规则表达式中的多个条件求值。
以下验证规则会检查新数据是否为少于 100 个字符的字符串:
".validate": "newData.isString() && newData.val().length < 100"
||(或)
如果规则表达式中的一个操作数为 true,则求值结果为 true。
在此示例中,只要旧数据或新数据不存在,我们就可以写入。换言之,如果我们要删除或创建数据,但没有更新数据,我们可以写入数据。
".write": "!data.exists() || !newData.exists()"
!(非)
如果单个操作数为 false,则求值结果为 true。在规则表达式中,!运算符通常用于查看数据是否已写入某个位置。
以下规则仅当指定位置没有任何数据时允许写入权限:
".write": "!data.exists()"
>(大于)
用于检查某个值是否大于规则表达式中的另一个值。
此验证规则可检查要写入的字符串是否不为空字符串:
".validate": "newData.isString() && newData.val().length > 0"
<(小于)
用于检查某个值是否小于规则表达式中的另一个值。
以下验证规则会检查字符串是否少于 20 个字符:
".validate": "newData.isString() && newData.val().length < 20"
>=(大于或等于)
用于检查某个值是否大于或等于规则表达式中的另一个值。
此验证规则可检查要写入的字符串是否不为空字符串:
".validate": "newData.isString() && newData.val().length >= 1"
<=(小于或等于)
用于检查某个值是否小于或等于规则表达式中的另一个值。
此验证规则可确保以后不会添加新数据:
".validate": "newData.val() <= now"
?(三元运算符)
用于对条件规则表达式求值。
三元运算符接受三个运算数。? 前面的操作数,是条件。如果条件计算结果为 true,则评估第二个操作数。如果条件为 false,则对第三个操作数进行求值。
对于以下验证规则,新值可以是数字或布尔值。如果为数字,则必须大于 0。
".validate": "newData.isNumber() ? newData.val() > 0 : newData.isBoolean()"