Cấu trúc các quy tắc bảo mật của Cloud Firestore

Các quy tắc bảo mật của Cloud Firestore cho phép bạn kiểm soát quyền truy cập vào các tài liệu và bộ sưu tập trong cơ sở dữ liệu của mình. Cú pháp quy tắc linh hoạt cho phép bạn tạo các quy tắc khớp với bất kỳ thứ gì, từ tất cả lượt ghi vào toàn bộ cơ sở dữ liệu cho đến các thao tác trên một tài liệu cụ thể.

Hướng dẫn này mô tả cú pháp và cấu trúc cơ bản của quy tắc bảo mật. Hãy kết hợp cú pháp này với các điều kiện của quy tắc bảo mật để tạo các tập quy tắc hoàn chỉnh.

Khai báo dịch vụ và cơ sở dữ liệu

Quy tắc bảo mật của Cloud Firestore luôn bắt đầu bằng nội dung khai báo sau:

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

Nội dung khai báo service cloud.firestore giúp áp dụng các quy tắc trong Cloud Firestore, giúp ngăn chặn xung đột giữa các Quy tắc và quy tắc bảo mật của Cloud Firestore cho các sản phẩm khác như Cloud Storage.

Nội dung khai báo match /databases/{database}/documents chỉ định rằng các quy tắc phải khớp với mọi cơ sở dữ liệu Cloud Firestore trong dự án. Hiện tại, mỗi dự án chỉ có một cơ sở dữ liệu duy nhất có tên là (default).

Quy tắc đọc/ghi cơ bản

Các quy tắc cơ bản bao gồm một câu lệnh match chỉ định một đường dẫn tài liệu và một biểu thức allow nêu chi tiết thời điểm cho phép đọc dữ liệu đã chỉ định:

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

    // Match any document in the 'cities' collection
    match /cities/{city} {
      allow read: if <condition>;
      allow write: if <condition>;
    }
  }
}

Tất cả câu lệnh so khớp phải trỏ đến tài liệu, chứ không phải bộ sưu tập. Câu lệnh so khớp có thể trỏ đến một tài liệu cụ thể, như trong match /cities/SF hoặc sử dụng ký tự đại diện để trỏ đến bất kỳ tài liệu nào trong đường dẫn được chỉ định, như trong match /cities/{city}.

Trong ví dụ trên, câu lệnh so khớp sử dụng cú pháp ký tự đại diện {city}. Tức là quy tắc này áp dụng cho mọi tài liệu trong tập hợp cities, chẳng hạn như /cities/SF hoặc /cities/NYC. Khi biểu thức allow trong câu lệnh so khớp được đánh giá, biến city sẽ phân giải thành tên tài liệu về thành phố, chẳng hạn như SF hoặc NYC.

Toán tử chi tiết

Trong một số trường hợp, bạn nên chia readwrite thành các thao tác chi tiết hơn. Ví dụ: ứng dụng của bạn có thể muốn thực thi nhiều điều kiện khi tạo tài liệu hơn là khi xoá tài liệu. Hoặc bạn nên cho phép đọc từng tài liệu nhưng từ chối các truy vấn lớn.

Quy tắc read có thể được chia thành getlist, trong khi quy tắc write có thể được chia thành create, updatedelete:

service cloud.firestore {
  match /databases/{database}/documents {
    // A read rule can be divided into get and list rules
    match /cities/{city} {
      // Applies to single document read requests
      allow get: if <condition>;

      // Applies to queries and collection read requests
      allow list: if <condition>;
    }

    // A write rule can be divided into create, update, and delete rules
    match /cities/{city} {
      // Applies to writes to nonexistent documents
      allow create: if <condition>;

      // Applies to writes to existing documents
      allow update: if <condition>;

      // Applies to delete operations
      allow delete: if <condition>;
    }
  }
}

Dữ liệu phân cấp

Dữ liệu trong Cloud Firestore được sắp xếp thành các tập hợp tài liệu và mỗi tài liệu có thể mở rộng hệ phân cấp thông qua các tập hợp con. Bạn cần phải hiểu cách các quy tắc bảo mật tương tác với dữ liệu phân cấp.

Hãy xem xét tình huống mà mỗi tài liệu trong tập hợp cities chứa một bộ sưu tập con landmarks. Các quy tắc bảo mật chỉ áp dụng cho đường dẫn đã khớp, vì vậy, các chế độ kiểm soát quyền truy cập được xác định trong tập hợp cities không áp dụng cho bộ sưu tập con landmarks. Thay vào đó, hãy viết các quy tắc rõ ràng để kiểm soát quyền truy cập vào các tập hợp con:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      allow read, write: if <condition>;

        // Explicitly define rules for the 'landmarks' subcollection
        match /landmarks/{landmark} {
          allow read, write: if <condition>;
        }
    }
  }
}

Khi lồng các câu lệnh match, đường dẫn của câu lệnh match bên trong luôn tương ứng với đường dẫn của câu lệnh match bên ngoài. Do đó, các tập hợp quy tắc sau đây tương đương với nhau:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      match /landmarks/{landmark} {
        allow read, write: if <condition>;
      }
    }
  }
}
service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city}/landmarks/{landmark} {
      allow read, write: if <condition>;
    }
  }
}

Ký tự đại diện đệ quy

Nếu bạn muốn các quy tắc áp dụng cho một hệ phân cấp sâu tuỳ ý, hãy dùng cú pháp ký tự đại diện đệ quy, {name=**}. Ví dụ:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

Khi sử dụng cú pháp ký tự đại diện đệ quy, biến ký tự đại diện sẽ chứa toàn bộ phân đoạn đường dẫn phù hợp, ngay cả khi tài liệu nằm trong bộ sưu tập con được lồng sâu. Ví dụ: các quy tắc được liệt kê ở trên sẽ khớp với một tài liệu tại /cities/SF/landmarks/coit_tower và giá trị của biến document sẽ là SF/landmarks/coit_tower.

Tuy nhiên, hãy lưu ý rằng hành vi của ký tự đại diện đệ quy phụ thuộc vào phiên bản quy tắc.

Phiên bản 1

Theo mặc định, các quy tắc bảo mật sử dụng phiên bản 1. Trong phiên bản 1, các ký tự đại diện đệ quy khớp với một hoặc nhiều mục đường dẫn. Các tập hợp này không khớp với đường dẫn trống, vì vậy match /cities/{city}/{document=**} khớp với các tài liệu trong tập hợp con chứ không khớp với các tài liệu trong tập hợp cities, trong khi match /cities/{document=**} khớp với cả hai tài liệu trong tập hợp cities và tập hợp con.

Ký tự đại diện đệ quy phải ở cuối câu lệnh so khớp.

Phiên bản 2

Trong phiên bản 2 của các quy tắc bảo mật, các ký tự đại diện đệ quy khớp với 0 hoặc nhiều mục đường dẫn. match/cities/{city}/{document=**} khớp với các tài liệu trong mọi tập hợp con cũng như các tài liệu trong tập hợp cities.

Bạn phải chọn sử dụng phiên bản 2 bằng cách thêm rules_version = '2'; ở đầu các quy tắc bảo mật:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the cities collection as well as any document
    // in a subcollection.
    match /cities/{city}/{document=**} {
      allow read, write: if <condition>;
    }
  }
}

Bạn có thể có tối đa một ký tự đại diện đệ quy cho mỗi câu lệnh so khớp. Tuy nhiên, trong phiên bản 2, bạn có thể đặt ký tự đại diện này ở bất cứ đâu trong câu lệnh so khớp. Ví dụ:

rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the songs collection group
    match /{path=**}/songs/{song} {
      allow read, write: if <condition>;
    }
  }
}

Nếu dùng truy vấn của nhóm thu thập, bạn phải sử dụng phiên bản 2, hãy xem bài viết bảo mật các truy vấn của nhóm thu thập.

Câu lệnh trùng khớp chồng chéo

Một tài liệu có thể khớp với nhiều câu lệnh match. Trong trường hợp nhiều biểu thức allow khớp với một yêu cầu, quyền truy cập sẽ được cho phép nếu bất kỳ điều kiện nào là true:

service cloud.firestore {
  match /databases/{database}/documents {
    // Matches any document in the 'cities' collection.
    match /cities/{city} {
      allow read, write: if false;
    }

    // Matches any document in the 'cities' collection or subcollections.
    match /cities/{document=**} {
      allow read, write: if true;
    }
  }
}

Trong ví dụ trên, mọi lượt đọc và ghi vào tập hợp cities sẽ được cho phép vì quy tắc thứ hai luôn là true, mặc dù quy tắc đầu tiên luôn là false.

Giới hạn đối với quy tắc bảo mật

Khi bạn làm việc với các quy tắc bảo mật, hãy lưu ý các giới hạn sau:

Giới hạn Thông tin chi tiết
Số lệnh gọi tối đa là exists(), get()getAfter() trong mỗi yêu cầu
  • 10 đối với yêu cầu một tài liệu và yêu cầu truy vấn.
  • 20 để đọc nhiều tài liệu, giao dịch và ghi hàng loạt. Giới hạn trước đó là 10 cũng áp dụng cho mỗi thao tác.

    Ví dụ: giả sử bạn tạo một yêu cầu ghi hàng loạt với 3 thao tác ghi và các quy tắc bảo mật của bạn sử dụng 2 lệnh gọi truy cập tài liệu để xác thực từng lượt ghi. Trong trường hợp này, mỗi lượt ghi sử dụng 2 trong số 10 lệnh gọi truy cập, còn yêu cầu ghi theo lô sử dụng 6/20 lệnh gọi truy cập.

Nếu vượt quá một trong hai giới hạn này, ứng dụng sẽ gặp lỗi bị từ chối cấp quyền.

Một số lệnh gọi truy cập vào tài liệu có thể được lưu vào bộ nhớ đệm và các lệnh gọi được lưu vào bộ nhớ đệm sẽ không được tính vào giới hạn này.

Độ sâu câu lệnh match lồng nhau tối đa 10
Độ dài đường dẫn tối đa trong các phân đoạn đường dẫn được cho phép trong một tập hợp các câu lệnh match lồng nhau 100
Số biến thể chụp đường dẫn tối đa được phép trong một tập hợp các câu lệnh match lồng nhau 20
Độ sâu lệnh gọi hàm tối đa 20
Số lượng đối số tối đa của hàm 7
Số liên kết biến tối đa let trên mỗi hàm 10
Số lệnh gọi hàm đệ quy hoặc theo chu kỳ tối đa 0 &lpar;không được phép&rpar;
Số biểu thức tối đa được đánh giá trong mỗi yêu cầu 1.000
Kích thước tối đa của bộ quy tắc Quy tắc phải tuân theo hai giới hạn kích thước:
  • giới hạn 256 KB cho kích thước của nguồn văn bản của bộ quy tắc được xuất bản từ bảng điều khiển của Firebase hoặc từ CLI bằng cách sử dụng firebase deploy.
  • giới hạn 250 KB cho kích thước của bộ quy tắc được biên dịch, dẫn đến khi Firebase xử lý nguồn và kích hoạt nguồn này trên phần phụ trợ.

Các bước tiếp theo