Firebase Cloud Storage 安全性規則用於確定誰對 Cloud Storage 中儲存的檔案具有讀寫存取權限,以及檔案的結構方式及其包含的元資料。雲端儲存安全規則由考慮request
和resource
以允許或拒絕所需操作(例如上傳文件或檢索文件元資料)的規則組成。這些參考文件涵蓋規則類型、 request
和resource
的屬性、雲端儲存安全規則所使用的資料類型以及錯誤的發生方式。
規則
rule
是一個表達式,透過計算來決定是否允許request
執行所需的操作。
類型
允許
allow
規則由方法(例如read
或write
以及可選條件組成。執行規則時,會評估條件,如果條件評估為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 | 與該使用者帳戶關聯的所有身分的字典。字典的鍵可以是以下任一: 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 | 與帳戶關聯的tenantId(如果存在)。例如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
包含檔案大小(以位元組為單位)的 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
類型表示布林true
或false
值。
allow read: if true; // always succeeds allow write: if false; // always fails
比較
可以使用==
運算子!=
來比較布林值。
布林運算
手術 | 表達 |
---|---|
AND | x && y |
OR | x || y |
NOT | !x |
操作短路,並且可以傳回true
、 false
或Error 。
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 位元值,浮點數是符合 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
(不包含)。如果未指定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
僅包含year
、 month
和day
的timestamp
值。
// 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
列表包含值的有序數組,其類型可以是: null
、 bool
、 int
、 float
、 string
、 path
、 list
、 map
、 timestamp
或duration
。
給定list
類型的x
和y
以及int
類型的i
和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';
錯誤
誤差評估
遇到錯誤時,Firebase Cloud Storage 安全性規則會繼續評估。這很有用,因為條件&&
和||
如果條件分別短路為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');