# Firebase with Android Studio part-13 : Security Rules with Firestore
## 開始吧
* 在Fire Store選取"規則"分頁,可以看到預設的Rules

### 預設值
* rules_version是用於編寫Firebase rule的語言版本,目前最新版是2,如果沒寫這一行,預設會用1
* service cloud.firestore是描述底下的rule套用於firestore這個服務
* match /databases/{database}/documents裡面就是要放定義的rule了
```javascript=
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if
request.time < timestamp.date(2021, 8, 5);
}
}
}
```
### match區塊
* 它定義了rule適用的路徑或者是集合
* match區塊內必須包含allow語句
* match可以用巢狀結構
* 巢狀match路徑必須相對於父層的路徑
* 如上方預設值,第一層match路徑指向所有集合的documents,巢狀match指向該documents底下所有的document
### allow區塊
* 這個區塊就是定義實際的規則
| 方法 | 請求類型 |
| ------ | -------------------------- |
| 簡易 | ---------------- |
| read | 任何類型的讀取請求 |
| write | 任何類型的寫請求 |
| 標準 | ----------------- |
| get | 對單個文檔或文件的讀取請求 |
| list | 查詢和集合的讀取請求 |
| create | 編寫新文檔或文件 |
| update | 寫入現有文檔或文件 |
| delete | 刪除數據 |
### 試著修改預設值
* 這邊建立兩個集合:country & level
* 各自存放兩個文件:taiwan & thailand
* 各自存放一個欄位:population & write


```javascript=
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
//從底下這邊開始修改
//底下match區塊是我們rule的作用區域是level這個集合,{}裡面放測試的路徑,稍後測試會提到
match /level/{level} {
//底下是rule本身,允許讀寫只要它的發出請求時間在xxx之前,這是之前我們創建資料庫選擇測試模式,30天後自動刪除的原因
allow read, write: if
request.time < timestamp.date(2021, 8, 5);
}
//底下我們替country這個集合寫一個rule,讀取我們直接打開,那寫入的部分,我們給他條件,在country這個集合底下的{文件},它的欄位population <500就可以寫入
match /country/{country} {
allow read: if true;
allow write:if resource.data.population < 500;
}
}
}
```
* 使用測試工具

* 輸入條件
* 要測試寫入,所以類型選update
* 位置:因為要測試country這個集合
* country/後面就是要放文件,對應到code的{}裡面

* 建立文件
* 建立我們要測試的條件欄位
* 我們的規則寫<500,所以這邊可以填個600做測試

* 就可以按執行察看結果
* 假設我們針對單一文件寫rule
* 針對不同文件定義不同條件
```javascript=
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /level/{level} {
allow read, write: if
request.time < timestamp.date(2021, 8, 5);
}
//父層作用範圍把它定義在country這個集合
match /country {
//再用巢狀定義在taiwan這個文件
match /taiwan {
allow write:if resource.data.population > 500;
allow read: if true;
}
//巢狀定義在thailand這個文件
match /thailand {
allow read: if true
allow write:if resource.data.population >1000
}
}
}
}
```

* 如果要判斷某個欄位要等於某個值才允許寫入
* 這邊比較奇怪的是如果不寫request就不行
* 但上面的例子用resource.data.population >1000卻是正常的,我試著把request加在這前面卻也可以正常執行...謎!!!
```javascript=
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /level/{level} {
allow read: if true;
//透過request取得can_write這個欄位是否為true
allow write: if request.resource.data.can_write == true;
}
}
}
```
* 如果A集合的文件寫入條件需要B集合的文件判斷是否有權限才能寫入呢?
* 用get(),/databases/$(database)/documents/,這是預設寫法,後面接續填入目標集合跟文件
* 底下的規則是,要寫入country的thailand文件,它需要population大於500,而且level這個集合的mamber文件中的can_write欄位必須為true
```javascript=
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /level/{level} {
allow read: if true;
allow write: if request.resource.data.can_write == true;
// request.time < timestamp.date(2021, 8, 5);
}
match /country {
match /taiwan {
allow write:if resource.data.population > 500;
allow read: if true;
}
match /thailand {
allow read: if true
//這裡用&&加入第二個條件
allow write:if resource.data.population >1000 &&
get(/databases/$(database)/documents/level/member).data.can_write == true;
}
}
}
}
```
官方文件還有很多內容[來看看吧](https://firebase.google.com/docs/rules/rules-language?authuser=0#storage)
參考資料
[Philipp Lackner's channel](https://www.youtube.com/watch?v=C999kVz96_w)
###### tags: `Firebase` `kotlin` `Android`