iT邦幫忙

2025 iThome 鐵人賽

DAY 27
0
自我挑戰組

攜手 AI 從零開始打造一款 Flutter 應用程式系列 第 27

Day 27: 為資料庫上鎖 - 撰寫 Firestore 安全規則

  • 分享至 

  • xImage
  •  

前言

大家好,歡迎來到第二十七天!在 Day 26,我們成功地將「省錢拍拍」打包成了可以發布的 Android AAB 檔案。我們的 App 離正式上架只差一步之遙。但在我們將它交給全世界的使用者之前,必須先處理一個極度重要的安全問題

回想在 Day 11,為了開發方便,我們將 Firestore 資料庫設定為「測試模式」。這個模式的規則如下:

allow read, write: if request.time < timestamp.date(2025, 10, 25);

這意味著,在一個月的寬限期內,任何人,無論是否登入,只要知道我們專案的 ID,就可以對我們的資料庫進行任意的讀、寫、刪除!這就像開了一家銀行,卻沒有鎖上金庫的大門,是絕對不能接受的。

今天,我們將扮演「資安工程師」的角色,學習 Firestore 安全規則的基本語法,並為我們的資料庫部署一條最核心、最重要的安全規則:「使用者只能讀寫屬於自己的資料」。

Step 1: 了解 Firestore 安全規則的運作方式

Firestore 安全規則不是寫在 Flutter 程式碼裡的,而是直接部署在 Firebase 雲端上。它就像一個站在你資料庫門口的警衛,每一筆來自 App 的讀寫請求,都必須先經過它的盤問和批准。

  • 請求 (Request):當 App 執行 ...add(...)...get() 時,就會發送一個包含使用者身份 (request.auth) 和目標路徑 (request.path) 等資訊的請求。
  • 規則 (Rules):我們撰寫的規則會檢查這些資訊,例如:「這個請求的使用者 UID,是否等於他想要存取的文件路徑上的 UID?」
  • 批准/拒絕 (Allow/Deny):如果規則回傳 true,請求通過;如果回傳 false 或沒有任何規則匹配,請求將被拒絕。

Step 2: 撰寫我們的核心安全規則

  1. 前往 Firebase 控制台:打開我們的 Firebase 專案,在左側導航欄點擊「建構」>「Firestore Database」。
  2. 選擇「規則」分頁:在頁面頂部,點擊「規則」分頁。你會看到目前的測試模式規則。
  3. 用新規則替換:將編輯器中的所有內容,用以下這段新的、安全的規則完全替換。
rules_version = '2';

service cloud.firestore {
  match /databases/{database}/documents {

    // 匹配 users 集合下的所有文件
    match /users/{userId} {
      // 允許使用者讀取或更新自己的個人資料文件 (例如 email, 暱稱)
      // 條件:請求者的 UID 必須等於路徑上的 userId
      allow read, update: if request.auth != null && request.auth.uid == userId;
      
      // 允許使用者建立自己的個人資料文件
      // 條件:請求者的 UID 必須等於文件 ID,且文件尚不存在
      allow create: if request.auth != null && request.auth.uid == userId;

      // 匹配 users/{userId} 底下的 transactions 子集合
      match /transactions/{transactionId} {
        // 允許對 transactions 子集合進行所有操作 (CRUD)
        // 條件:請求者的 UID 必須等於這個子集合所屬的 user 的 ID
        allow write: if request.auth != null && request.auth.uid == userId;
      }
    }
  }
}

Step 3: 理解並解析規則

  • match /users/{userId}: 這條規則匹配所有指向 users 集合下任一文件的路徑。{userId} 是一個萬用字元,它會捕捉路徑中的那段字串(也就是使用者的 UID)。
  • allow read, update: if request.auth.uid == userId;
    • allow read, update: 賦予「讀取」和「更新」的權限。
    • if ...: 這是條件判斷式。
    • request.auth != null: 檢查使用者是否已登入。
    • request.auth.uid: 這是發出請求的使用者的 UID,由 Firebase Authentication 自動提供。
    • == userId: 將請求者的 UID 與他試圖存取的路徑中的 userId 萬用字元進行比較。
    • 總結:只有當登入者的 UID 和他想讀取的使用者文件 ID 完全相同時,才允許操作。User A 無法讀取 User B 的資料。
  • match /transactions/{transactionId}: 這是一個巢狀規則,它匹配 users/{userId} 文件底下的 transactions 子集合中的任一文件。
  • allow read, write: if request.auth.uid == userId;
    • 這個巢狀規則繼承了外層的 {userId} 萬用字元。
    • writecreate、update、delete 的統稱,代表允許完整的寫入權限。
    • 總結:當一個請求指向 /users/USER_A_UID/transactions/SOME_ID 時,規則會檢查發出請求的人,其 request.auth.uid 是否等於外層路徑中的 USER_A_UID。如果是,就允許所有操作。

Step 4: 發布與測試

  1. 發布規則:在編輯器右上角,點擊藍色的「發布(Publish)」 按鈕。幾秒鐘後,你的資料庫就會受到新規則的保護。
  2. 模擬器測試:你可以使用 Firebase 控制台內建的「規則遊樂場」來模擬請求,測試規則是否如預期運作。

今日結語

今天我們為雲端金庫裝上了一把堅固、可靠的大鎖。我們學會了:

  1. Firestore 安全規則的基本運作原理。
  2. 如何使用 match、萬用字元 {}request.auth.uid 來定義權限。
  3. 撰寫並部署了一條核心安全規則:「使用者只能存取自己的資料」。

完成了這一步,我們才能放心地將 App 交給使用者。資料隱私與安全是任何一個負責任的 App 開發者都必須嚴肅對待的課題。

我們的 App 現在不僅功能完整,安全性也提升到了新的層級。但程式碼中還有一個小小的安全隱憂——我們的 Gemini API 金鑰。

明天,我們將處理最後一個安全議題:使用環境變數來管理我們的 API 金鑰,徹底告別將密鑰寫死在程式碼中的壞習慣。


上一篇
Day 26: 邁向市場的第一步 - 打包 Android 發布版 (AAB)
下一篇
Day 28: 保護你的金鑰 - 使用環境變數管理 API Key
系列文
攜手 AI 從零開始打造一款 Flutter 應用程式29
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言