雲端儲存參考的 Firebase 安全性規則

Firebase Cloud Storage 安全性規則用於確定誰對 Cloud Storage 中儲存的檔案具有讀寫存取權限,以及檔案的結構方式及其包含的元資料。雲端儲存安全規則由考慮requestresource以允許或拒絕所需操作(例如上傳文件或檢索文件元資料)的規則組成。這些參考文件涵蓋規則類型、 requestresource的屬性、雲端儲存安全規則所使用的資料類型以及錯誤的發生方式。

規則

rule是一個表達式,透過計算來決定是否允許request執行所需的操作。

類型

允許

allow規則由方法(例如readwrite以及可選條件組成。執行規則時,會評估條件,如果條件評估為true ,則允許所需的方法;否則,該方法將被拒絕。無條件的allow規則始終允許所需的方法。

// Always allow method
allow <method>;

// Allow method if condition is true
allow <method>: if <condition>;

目前, allow是唯一受支援的規則類型。

請求方法

read方法涵蓋了所有讀取檔案資料或元資料的請求,包括檔案下載和檔案元資料讀取。

// Always allow reads
allow read;

// Allow reads if condition evaluates to true
allow read: if <condition>;

write方法涵蓋了所有寫入檔案資料或元資料的請求,包括檔案上傳、檔案刪除、檔案元資料更新。

// Always allow writes
allow write;

// Allow writes if condition evaluates to true
allow write: if <condition>;

匹配

當使用者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} 。該變數可以在 match 語句中作為string存取。

// 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=**} 。多段通配符變數在 match 語句中可用作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 驗證 JWT ( request.auth.token ) 的聲明。

request.auth.token包含下列部分或全部按鍵:

場地描述
email與帳戶關聯的電子郵件地址(如果存在)。
email_verified如果使用者已驗證他們有權存取email地址,則為true 。一些提供者會自動驗證他們擁有的電子郵件地址。
phone_number與帳戶關聯的電話號碼(如果存在)。
name使用者的顯示名稱(如果已設定)。
sub用戶的 Firebase 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與帳戶關聯的tenantId(如果存在)。例如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

包含檔案大小(以位元組為單位)的 int。

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

包含檔案MD5 哈希值的字串。

// 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 雜湊值的字串。

// 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.存在

檢查 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是雲端儲存安全規則文件中的第一個聲明,並指定這些規則將應用於哪個服務。

姓名

name

將套用服務規則的名稱。目前唯一的值是firebase.storage

// Specify the service name
service firebase.storage {
  match /b/{bucket}/o {
    ...
  }
}

資料類型

規則語言允許您使用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

操作短路,並且可以傳回truefalseError

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 位元值,浮點數是符合 IEEE 754 標準的 64 位元值。當用於float值的比較和算術運算時, int類型的值將被強制轉換為float型。

比較

可以使用==!=><>=<=運算子對整數和浮點數進行比較和排序。

算術

整數和浮點數可以進行加、減、乘、除、取模和取反:

手術表達
添加x + y
減法x - y
乘法x * y
分配x / y
模數x % y
否定-x

數學函數

Firebase Cloud Storage 安全性規則也提供了許多數學輔助函數來簡化表達式:

功能描述
math.ceil(x)數值上限
math.floor(x)數值下限
math.round(x)將輸入值舍入為最接近的 int
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

僅包含yearmonthdaytimestamp值。

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

秒值作為 int,從 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

給定list類型的xy以及int類型的ij

創建

若要建立列表,請在括號之間新增值:

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

錯誤

誤差評估

遇到錯誤時,Firebase Cloud Storage 安全性規則會繼續評估。這很有用,因為條件&&||如果條件分別短路為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');