面向 Cloud Storage 的 Firebase 安全规则参考

Cloud StorageFirebase Security Rules 用于确定谁具有读写权限 存储在 Cloud Storage 中的文件,以及文件的结构 以及其中包含的元数据Cloud Storage Security Rules由多个规则组成 可以考虑使用 requestresource 来允许或拒绝所需的操作,例如 例如上传文件或检索文件元数据。这些参考文档的内容包括 规则类型、requestresource 的属性、数据 Cloud Storage Security Rules 使用的类型以及错误的发生方式。

规则

rule 是一个表达式,用于评估以确定 request 是否 执行所需的操作。

类型

允许

allow 规则包含一个方法(例如 readwrite), 可选条件。在执行规则时,系统会评估条件,并且 如果条件的计算结果为 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 与此用户账号关联的所有身份的字典。字典的键可以是以下任一值:emailphonegoogle.comfacebook.comgithub.comtwitter.com。字典的值是与账号关联的每个身份提供方的唯一标识符的数组。例如,auth.token.firebase.identities["google.com"][0] 包含与该账号关联的第一个 Google 用户 ID。
firebase.sign_in_provider 用于获取此令牌的登录服务提供方。可以是以下任一字符串:custompasswordphoneanonymousgoogle.comfacebook.comgithub.comtwitter.com
firebase.tenant 与账号关联的租户 ID(如有)。例如 tenant2-m6tyz

如果使用自定义身份验证,request.auth.token 还包含任何自定义 声明。

当未经身份验证的用户发出请求时,request.authnull

// 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

serviceCloud 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 类型表示布尔值 truefalse

allow read: if true;   // always succeeds
allow write: if false; // always fails

比较

您可以使用 == 运算符 != 比较布尔值。

布尔值运算

操作 表达式
AND x && y
OR x || y
NOT !x

操作短路,可以返回 truefalse错误

allow read: if true || false;   // always succeeds, short circuits at true
allow write: if false && true; // always fails, short circuits at false

intfloat

intfloat 类型表示数字。整数包括 01-2 等。 ,而浮点数为 1.0-2.03.33 等。

整数是有符号的 64 位值,浮点值是符合 64 位 IEEE 754 标准的值。 在比较运算中使用时,int 类型的值将被强制转换为 float 值为 float 的算术运算。

比较

您可以使用 ==!=>< 比较整数和浮点数,并对其进行排序。 >=<= 运算符。

算术

整数和浮点数可以进行加减法运算、乘法、除法、取模和运算; 否定:

操作 表达式
添加 x + y
x - y
x * y
x / y
取模 x % y
取反 -x

数学函数

Cloud StorageFirebase 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 (不含边界值)。如果未指定 ij,则它们会默认为 0,而 字符串,但必须至少指定 ij 才能使范围有效。

// Allow reads of files that begin with 'abcdef'
match /{fileName} {
  allow read: if fileName[0:6] == 'abcdef';
}

如果提供索引,indexrange 运算符会产生错误 超出字符串边界。

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 值,仅包含 yearmonthday

// 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

列表包含一个有序的值数组,值的类型如下:nullboolintfloatstringpathlistmaptimestampduration

假定 xy 的类型为 listi 以及类型为 intj

创建

如需创建列表,请在方括号之间添加值:

// 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(不含)。如果 ij 未指定,它们分别默认为 0 和列表大小,但 必须至少指定 ij 才能使范围有效。

// 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

映射包含键值对,其中键是字符串,值可以是任何值 /nullboolintfloatstringpathlistmaptimestampduration

创建

如需创建映射,请在大括号内添加键值对:

// 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 StorageFirebase Security Rules 在遇到错误时继续评估。 这很有用,因为条件 &&|| 表达式可以吸收错误 如果该条件会短路到 falsetrue 。例如:

表达式 结果
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');