Cloud Storage 的 Firebase Security Rules 用于确定谁具有读写权限
存储在 Cloud Storage 中的文件,以及文件的结构
以及其中包含的元数据Cloud Storage Security Rules由多个规则组成
可以考虑使用 request
和 resource
来允许或拒绝所需的操作,例如
例如上传文件或检索文件元数据。这些参考文档的内容包括
规则类型、request
和 resource
的属性、数据
Cloud Storage Security Rules 使用的类型以及错误的发生方式。
规则
rule
是一个表达式,用于评估以确定 request
是否
执行所需的操作。
类型
允许
allow
规则包含一个方法(例如 read
或 write
),
可选条件。在执行规则时,系统会评估条件,并且
如果条件的计算结果为 true
,则允许使用所需方法;否则
此方法会被拒绝。不含条件的 allow
规则始终允许
所需的方法
// Always allow method allow <method>; // Allow method if condition is true allow <method>: if <condition>;
目前,allow
是唯一支持的规则类型。
请求方法
Read
read
方法涵盖读取文件数据或元数据的所有请求,
包括文件下载和文件元数据读取。
// Always allow reads allow read; // Allow reads if condition evaluates to true allow read: if <condition>;
Write
write
方法涵盖写入文件数据或元数据的所有请求,
包括文件上传、文件删除和文件元数据更新。
// Always allow writes allow write; // Allow writes if condition evaluates to true allow write: if <condition>;
Match
当用户 request
(例如文件上传或下载)时,系统会执行规则
与规则覆盖的文件路径匹配。match
由路径和正文组成,
该模板必须至少包含一条 allow
规则。如果没有匹配的路径,则请求
已被拒绝。
您可以使用 match
完整命名路径,也可以插入通配符以匹配所有路径
符合特定模式的路径。
路径细分
single_segment
您可以使用单路径段来创建与存储的文件匹配的规则 在 Cloud Storage 中。
// Allow read at "path" if condition evaluates to true match /path { allow read: if <condition>; }
也允许使用多个路径段和嵌套路径:
// Allow read at "path/to/object" if condition evaluates to true match /path { match /to { match /object { allow read: if <condition>; } } }
{single_segment_wildcard}
如果要将规则应用于同一路径下的多个文件,您可以使用
通配符路径段以匹配特定路径下的所有文件。通配符变量
将变量用大括号括起来,可在路径中进行声明:{variable}
。
此变量可作为 string
在 match 语句中访问。
// Allow read at any path "/*", if condition evaluates to true match /{single_path} { // Matches "path", "to", or "object" but not "path/to/object" allow read: if <condition>; }
多个路径段和嵌套路径也可以包含通配符:
// Allow read at any path "/path/*/newPath/*", if condition evaluates to true match /path/{first_wildcard} { match /newPath/{second_wildcard} { // Matches "path/to/newPath/newObject" or "path/from/newPath/oldObject" allow read: if <condition>; } }
{multi_segment_wildcard=**}
如果要在路径上或路径之下匹配任意数量的路径段,您可以使用 多段通配符,该通配符将匹配所有 位置。这对于为用户提供自己的自由形式非常有用 或创建与许多不同路径段(例如 创建一组可公开读取的文件,或要求对 所有写入操作)。
多段通配符路径的声明方式与单段类似。
通配符,并在变量末尾添加 =**
:
{variable=**}
。匹配中有一个多段通配符变量
声明为 path
对象。
// Allow read at any path "/**", if condition evaluates to true match /{multi_path=**} { // Matches anything at or below this, from "path", "path/to", "path/to/object", ... allow read: if <condition>; }
请求
request
变量在条件内提供,用于表示
请求。request
变量包含很多
属性,可用于决定是否允许传入请求。
属性
auth
当经过身份验证的用户针对 Cloud Storage 发出请求时,
auth
变量由用户的 uid
(request.auth.uid
) 填充,如下所示
以及 Firebase Authentication JWT (request.auth.token
) 的声明。
request.auth.token
包含以下部分或全部键:
字段 | 说明 |
---|---|
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 |
如果使用自定义身份验证,request.auth.token
还包含任何自定义
声明。
当未经身份验证的用户发出请求时,request.auth
为 null
。
// Allow requests from authenticated users allow read, write: if request.auth != null;
path
path
变量包含正在执行 request
的路径
。
// Allow a request if the first path segment equals "images" allow read, write: if request.path[0] == 'images';
resource
resource
变量包含正在上传的文件的元数据或
更新现有文件的元数据。这与
resource
变量,该变量包含当前的文件元数据,
而不是新的元数据。
// Allow a request if the new value is smaller than 5MB allow read, write: if request.resource.size < 5 * 1024 * 1024;
request.resource
包含 resource
中的以下属性:
属性 |
---|
name |
bucket |
metadata |
size |
contentType |
time
time
变量包含表示当前服务器时间的时间戳
请求的评估时间。你可以用它来提供基于时间的访问权限
文件,例如:仅允许在某个特定日期之前上传文件;
或者仅允许在文件上传后最长一小时内读取文件。
// Allow a read if the file was created less than one hour ago allow read: if request.time < resource.timeCreated + duration.value(1, 'h');
资源
resource
变量包含以下项目的文件元数据:
Cloud Storage,例如文件名、大小、创建时间和
自定义元数据
属性
name
包含文件全名(包括文件路径)的字符串。
// Allow reads if the resource name is "path/to/object" allow read: if resource.name == 'path/to/object'
bucket
包含 Google Cloud Storage 的字符串 存储此文件的存储分区中。
// Allow reads of all resources in your bucket allow read: if resource.bucket == '<your-cloud-storage-bucket>'
generation
包含 Google Cloud Storage 的 int 对象生成 文件。用于对象版本控制。
// Allow reads if the resource matches a known object version allow read: if resource.generation == <known-generation>
metageneration
包含 Google Cloud Storage 的 int 对象元数据生成 文件副本。用于对象版本控制。
// Allow reads if the resource matches a known object metadata version allow read: if resource.metageneration == <known-generation>
size
包含文件大小(以字节为单位)的整数。
// Allow reads if the resource is less than 10 MB allow read: if resource.size < 10 * 1024 * 1024;
timeCreated
表示文件的创建时间的时间戳。
// Allow reads if the resource was created less than an hour ago allow read: if resource.timeCreated < request.time + duration.value(60, "m")
updated
表示文件上次更新时间的时间戳。
// Allow reads if the resource was updated less than an hour ago allow read: if resource.updated < request.time + duration.value(60, "m")
md5Hash
// Allow writes if the hash of the uploaded file is the same as the existing file allow write: if request.resource.md5Hash == resource.md5Hash;
crc32c
包含 crc32c hash 文件。
// Allow writes if the hash of the uploaded file is the same as the existing file allow write: if request.resource.crc32c == resource.crc32c;
etag
一个包含 etag 的字符串, 文件。
// Allow writes if the etag matches a known object etag allow write: if resource.etag == <known-generation>
contentDisposition
包含文件内容处置的字符串。
// Allow reads if the content disposition matches a certain value allow read: if resource.contentDisposition == 'inlined';
contentEncoding
包含文件内容编码的字符串。
// Allow reads if the content is encoded with gzip allow read: if resource.contentEncoding == 'gzip';
contentLanguage
包含文件内容语言的字符串。
// Allow reads if the content language is Japanese allow read: if resource.contentLanguage == 'ja';
contentType
包含文件内容类型的字符串。
// Allow reads if the content type is PNG. allow read: if resource.contentType == 'image/png';
metadata
一个包含开发者提供的其他元数据的 Map<String, String>
字段。
// Allow reads if a certain metadata field matches a desired value allow read: if resource.metadata.customProperty == 'customValue';
firestore.get 和 firestore.exists
借助 firestore.get()
和 firestore.exists()
函数,您可以访问
Cloud Firestore 中的文档,以评估复杂的授权标准。
firestore.get()
和 firestore.exists()
函数都需要
完全指定的文档路径。使用变量为
firestore.get()
和 firestore.exists()
,您需要显式转义
变量使用 $(variable)
语法。
Firestore.get
获取 Cloud Firestore 文档的内容。
service firebase.storage { match /b/{bucket}/o { match /users/{club}/files/{fileId} { allow read: if club in firestore.get(/databases/(default)/documents/users/$(request.auth.uid)).data.memberships } } }
Firestore.exists
检查 Cloud Firestore 文档是否存在。
service firebase.storage { match /b/{bucket}/o { match /users/{userId}/photos/{fileId} { allow read: if firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.uid)) } } }
Service
service
是 Cloud Storage Security Rules 文件中的第一个声明,
指定这些规则将应用于哪些服务。
名称
name
服务规则的名称将应用于。唯一的当前值是
firebase.storage
。
// Specify the service name service firebase.storage { match /b/{bucket}/o { ... } }
数据类型
Rules 语言允许您使用 is
运算符检查类型。
// For example
a is null
a is string
null
null
数据类型表示不存在的值。
allow read: if request.auth != null;
bool
bool
类型表示布尔值 true
或 false
。
allow read: if true; // always succeeds allow write: if false; // always fails
比较
您可以使用 ==
运算符 !=
比较布尔值。
布尔值运算
操作 | 表达式 |
---|---|
AND |
x && y |
OR |
x || y |
NOT |
!x |
操作短路,可以返回 true
、false
或
错误。
allow read: if true || false; // always succeeds, short circuits at true allow write: if false && true; // always fails, short circuits at false
int
和float
int
和 float
类型表示数字。整数包括 0
、1
、-2
等。
,而浮点数为 1.0
、-2.0
、3.33
等。
整数是有符号的 64 位值,浮点值是符合 64 位 IEEE 754 标准的值。
在比较运算中使用时,int
类型的值将被强制转换为 float
值为 float
的算术运算。
比较
您可以使用 ==
、!=
、>
、<
比较整数和浮点数,并对其进行排序。
>=
和 <=
运算符。
算术
整数和浮点数可以进行加减法运算、乘法、除法、取模和运算; 否定:
操作 | 表达式 |
---|---|
添加 | x + y |
减 | x - y |
乘 | x * y |
除 | x / y |
取模 | x % y |
取反 | -x |
数学函数
Cloud Storage 的 Firebase Security Rules 还提供了许多数学帮助程序 以下函数来简化表达式:
函数 | 说明 |
---|---|
math.ceil(x) |
数值的上限 |
math.floor(x) |
数值的底价 |
math.round(x) |
将输入值四舍五入为最接近的整数 |
math.abs(x) |
输入的绝对值 |
math.isInfinite(x) |
测试值是否为 ±∞ ,会返回 bool |
math.isNaN(x) |
测试值是否不是数字 NaN ,返回 bool |
string
比较
您可以使用 ==
、!=
、>
、<
、>=
和
<=
运算符。
串联
可以使用 +
运算符串联字符串。
// Concatenate a file name and extension 'file' + '.txt'
索引和范围
index
运算符 string[]
会返回包含字符
。
// Allow reads of files that begin with 'a' match /{fileName} { allow read: if fileName[0] == 'a'; }
range
运算符 string[i:j]
会返回一个包含
指定索引之间的 个字符,范围为 i
(含)到 j
(不含边界值)。如果未指定 i
或 j
,则它们会默认为 0,而
字符串,但必须至少指定 i
或 j
才能使范围有效。
// Allow reads of files that begin with 'abcdef' match /{fileName} { allow read: if fileName[0:6] == 'abcdef'; }
如果提供索引,index
和 range
运算符会产生错误
超出字符串边界。
size
返回字符串中的字符数。
// Allow files with names less than 10 characters match /{fileName} { allow write: if fileName.size() < 10; }
matches
执行正则表达式匹配,如果字符串与true
指定正则表达式用途
Google RE2 语法。
// Allow writes to files which end in ".txt" match /{fileName} { allow write: if fileName.matches('.*\\.txt') }
split
根据提供的正则表达式拆分字符串并返回 list
字符串。使用 Google RE2 语法。
// Allow files named "file.*" to be uploaded match /{fileName} { allow write: if fileName.split('.*\\..*')[0] == 'file' }
path
路径是类似于目录的名称,具有可选的模式匹配。通过
正斜杠 /
表示路径段的开头。
path
将 string
参数转换为 path
。
// Allow reads on a specific file path match /{allFiles=**} { allow read: if allFiles == path('/path/to/file'); }
timestamp
时间戳采用世界协调时间 (UTC),可能的值从 0001-01-01T00.00.00Z 开始 收货地址为 9999-12-31T23.59.59Z。
比较
您可以使用 ==
、!=
、>
、<
、>=
和
<=
运算符。
算术
时间戳支持在时间戳和时长之间进行加减运算,如 如下:
表达式 | 结果 |
---|---|
timestamp + duration |
timestamp |
duration + timestamp |
timestamp |
timestamp - duration |
timestamp |
timestamp - timestamp |
duration |
duration + duration |
duration |
duration - duration |
duration |
date
timestamp
值,仅包含 year
、month
和 day
。
// Allow reads on the same day that the resource was created. allow read: if request.time.date() == resource.timeCreated.date()
year
以整数表示的年份值,介于 1 到 9999 之间。
// Allow reads on all requests made before 2017 allow read: if request.time.year() < 2017
month
以整数形式表示的月份值,介于 1 到 12 之间。
// Allow reads on all requests made during the month of January allow read: if request.time.month() == 1;
day
一个月中的当前日期,以整数表示,介于 1 到 31 之间。
// Allow reads on all requests made during the first day of each month allow read: if request.time.day() == 1;
time
包含当前时间的 duration
值。
// Allow reads on all requests made before 12PM allow read: if request.time.time() < duration.time(12, 0, 0, 0);
hours
以整数形式表示的小时值,范围为 0 到 23。
// Allow reads on all requests made before 12PM allow read: if request.time.hours() < 12;
minutes
以整数表示的分钟数值,范围为 0 到 59。
// Allow reads during even minutes of every hour allow read: if request.time.minutes() % 2 == 0;
seconds
以整数形式表示的秒值,范围为 0 到 59。
// Allow reads during the second half of each minute allow read: if request.time.seconds() > 29;
nanos
以纳秒为单位的小数秒,以整数表示。
// Allow reads during the first 0.1 seconds of each second allow read: if request.time.nanos() < 100000000;
dayOfWeek
周几,从 1(星期一)到 7(星期日)
// Allow reads on weekdays (Monday to Friday) allow read: if request.time.dayOfWeek() < 6;
dayOfYear
当前一年中的第几天,从 1 到 366。
// Allow reads every fourth day allow read: if request.time.dayOfYear() % 4 == 0;
toMillis
返回自 Unix 公元纪年以来的当前毫秒数。
// Allow reads if the request is made before a specified time allow read: if request.time.toMillis() < <milliseconds>;
duration
时长值以秒加上小数秒的形式表示, 纳秒。
比较
您可以使用 ==
、!=
、>
、<
、>=
和
<=
运算符。
算术
时长支持在时间戳和时长之间进行加减运算,例如 如下:
表达式 | 结果 |
---|---|
timestamp + duration |
timestamp |
duration + timestamp |
timestamp |
timestamp - duration |
timestamp |
timestamp - timestamp |
duration |
duration + duration |
duration |
duration - duration |
duration |
seconds
当前时长的秒数。必须介于 -315,576,000,000 之间 和 +315,576,000,000(含)之间的流量。
nanos
当前时长的小数秒(以纳秒为单位)。必须 介于 -999,999,999 和 +999,999,999(含)之间。对于非零秒和 非零纳秒,则两者的迹象必须一致。
duration.value
可以使用 duration.value(int magnitude, string units)
创建时长
函数,该函数基于给定量级和单位创建持续时间。
// All of these durations represent one hour: duration.value(1, "h") duration.value(60, "m") duration.value(3600, "s")
可能的 unit
包括:
时长 | unit |
---|---|
周 | w |
天 | d |
小时 | h |
分钟 | m |
秒 | s |
毫秒 | ms |
纳秒 | ns |
duration.time
您可以使用
duration.time(int hours, int minutes, int seconds, int nanoseconds)
函数,
该函数将创建由指定小时、分钟、秒和
纳秒。
// Create a four hour, three minute, two second, one nanosecond duration duration.time(4, 3, 2, 1)
list
列表包含一个有序的值数组,值的类型如下:null
、bool
、
int
、float
、string
、path
、list
、map
、timestamp
或 duration
。
假定 x
和 y
的类型为 list
和 i
以及类型为 int
的 j
创建
如需创建列表,请在方括号之间添加值:
// Create a list of strings ['apples', 'grapes', 'bananas', 'cheese', 'goats']
比较
您可以使用 ==
运算符 !=
比较列表。两个列表相等
要求所有值必须相同。
索引和范围
index
运算符 list[]
会返回
。
// Allow reads of all files that begin with 'a' match /{fileName} { allow read: if fileName[0] == 'a'; }
range
运算符 list[i:j]
会返回介于
指定索引,范围为 i
(含)到 j
(不含)。如果 i
或 j
未指定,它们分别默认为 0 和列表大小,但
必须至少指定 i
或 j
才能使范围有效。
// Allow reads of all files that begin with 'abcdef' match /{fileName} { allow read: if fileName[0:6] == 'abcdef'; }
in
如果所需值出现在列表中,则返回 true
;否则返回 false
存在。
// Allow read if a filename has the string 'txt' in it match /{fileName} { allow read: if 'txt' in fileName.split('\\.'); }
join
将一系列字符串合并为单个字符串,并以给定字符串分隔。
// Allow reads if the joined array is 'file.txt' allow read: if ['file', 'txt'].join('.') == 'file.txt';
size
列表中项目的数量。
// Allow read if there are three items in our list allow read: if ['foo', 'bar', 'baz'].size() == 3;
hasAll
如果列表中的所有值都存在,则返回 true
。
// Allow read if one list has all items in the other list allow read: if ['file', 'txt'].hasAll(['file', 'txt']);
map
映射包含键值对,其中键是字符串,值可以是任何值
/null
、bool
、int
、float
、string
、path
、list
、map
、
timestamp
或 duration
。
创建
如需创建映射,请在大括号内添加键值对:
// Create a map of strings to strings { 'mercury': 'mars', 'rain': 'cloud', 'cats': 'dogs', }
比较
您可以使用 ==
运算符 !=
比较地图。两个映射相等
要求两个映射中都存在所有键,并且所有值都相同。
索引
映射中的值可通过括号或点表示法来访问:
// Access custom metadata properties allow read: if resource.metadata.property == 'property' allow write: if resource.metadata['otherProperty'] == 'otherProperty'
如果键不存在,则返回 error
。
in
如果所需键出现在映射中,则返回 true
;如果不存在,则返回 false
存在。
// Allow reads if a property is present in the custom metadata allow read: if property in resource.metadata;
size
映射中的键数量。
// Allow reads if there's exactly one custom metadata key allow read: if resource.metadata.size() == 1;
keys
映射中所有键的列表。
// Allow reads if the first metadata key is 'myKey' allow read: if resource.metadata.keys()[0] == 'myKey';
values
映射中所有值的列表(按键顺序)。
// Allow reads if the first metadata value is 'myValue' allow read: if resource.metadata.values()[0] == 'myValue';
错误
错误评估
Cloud Storage 的 Firebase Security Rules 在遇到错误时继续评估。
这很有用,因为条件 &&
和 ||
表达式可以吸收错误
如果该条件会短路到 false
或 true
。例如:
表达式 | 结果 |
---|---|
error && true |
error |
error && false |
false |
error || true |
true |
error || false |
error |
导致错误的常见位置包括:除数为零、取值 列表或映射中,并且传递的值类型不正确 一个函数。
// Error if resource.size is zero allow read: if 1000000 / resource.size; // Error, key doesn't exist allow read: if resource.metadata.nonExistentKey == 'value'; // Error, no unit 'y' exists allow read: if request.time < resource.timeCreated + duration.value(1, 'y');