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

Cloud Firestore Security Rules 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ú pháp quy tắc linh hoạt cho phép bạn tạo các quy tắc khớp với mọi thứ, từ tất cả các thao tác ghi vào toàn bộ cơ sở dữ liệu đế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 bộ quy tắc hoàn chỉnh.

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

Cloud Firestore Security Rules luôn bắt đầu bằng phần khai báo sau:

service cloud.firestore {
  // The {database} wildcard allows the rules to reference any database,
  // but these rules are only active on databases where they are explicitly deployed.
  match /databases/{database}/documents {
    // ...
  }
}

Phần khai báo service cloud.firestore giới hạn phạm vi quy tắc cho Cloud Firestore, ngăn xung đột giữa Cloud Firestore Security Rules và quy tắc cho các sản phẩm khác như Cloud Storage.

Phần 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. Mặc dù một dự án có thể chứa tối đa 100 cơ sở dữ liệu, nhưng chỉ cơ sở dữ liệu đầu tiên được tạo mới được chỉ định là cơ sở dữ liệu mặc định.

Cloud Firestore Security Rules được áp dụng riêng cho từng cơ sở dữ liệu có tên trong dự án. Điều này có nghĩa là nếu tạo nhiều cơ sở dữ liệu, bạn phải quản lý và triển khai quy tắc cho từng cơ sở dữ liệu. Để biết hướng dẫn chi tiết về cách triển khai bản cập nhật, hãy xem bài viết Triển khai bản cập nhật.

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 đường dẫn tài liệu và một biểu thức allow nêu chi tiết thời điểm được 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 match phải trỏ đến tài liệu, không phải bộ sưu tập. Câu lệnh match 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 đã chỉ định, như trong match /cities/{city}.

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

Thao tác chi tiết

Trong một số trường hợp, bạn nên chia readwrite thành các thao tác thật chi tiết hơn. Ví dụ: ứng dụng của bạn có thể muốn thực thi các điều kiện khác nhau đối với việc tạo tài liệu so với việc xoá tài liệu. Hoặc bạn có thể muốn cho phép đọc một 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 bộ sưu tậ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 bộ sưu tập con. Bạn cần hiểu cách 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 trường hợp mỗi tài liệu trong bộ sưu tập cities chứa một bộ sưu tập con landmarks. Quy tắc bảo mật chỉ áp dụng ở đường dẫn đã khớp, vì vậy, các chế độ kiểm soát quyền truy cập được xác định trên bộ sưu tậ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 bộ sưu tậ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 bộ quy tắc sau đây là tương đương:

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 có độ sâu tuỳ ý, hãy sử 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 khớp, ngay cả khi tài liệu nằm trong một 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 nằm 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

Quy tắc bảo mật sử dụng phiên bản 1 theo mặc định. Trong phiên bản 1, ký tự đại diện đệ quy khớp với một hoặc nhiều mục đường dẫn. Các ký tự 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 bộ sưu tập con nhưng không khớp với các tài liệu trong bộ sưu tập cities, trong khi match /cities/{document=**} khớp với cả tài liệu trong bộ sưu tập cities và bộ sưu tập con.

Ký tự đại diện đệ quy phải nằm ở cuối câu lệnh match.

Phiên bản 2

Trong phiên bản 2 của quy tắc bảo mật, 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 bộ sưu tập con cũng như các tài liệu trong bộ sưu tậ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 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 match, nhưng trong phiên bản 2, bạn có thể đặt ký tự đại diện này ở bất kỳ vị trí nào trong câu lệnh match. 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 bạn sử dụng truy vấn nhóm bộ sưu tập, bạn phải sử dụng phiên bản 2, hãy xem bài viết bảo mật truy vấn nhóm bộ sưu tập.

Câu lệnh match trùng lặp

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, tất cả các thao tác đọc và ghi vào bộ sưu tậ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 quy tắc bảo mật

Khi làm việc với 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 exists(), get()getAfter() tối đa cho mỗi yêu cầu
  • 10 cho các yêu cầu một tài liệu và yêu cầu truy vấn.
  • 20 cho các thao tác đọc nhiều tài liệu, giao dịch, và thao tác ghi theo lô. 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 theo lô với 3 thao tác ghi và 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 mỗi thao tác ghi. Trong trường hợp này, mỗi thao tác ghi sử dụng 2 trong số 10 lệnh gọi truy cập và yêu cầu ghi theo lô sử dụng 6 trong số 20 lệnh gọi truy cập.

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

Một số lệnh gọi truy cập 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 không được tính vào giới hạn.

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

Các bước tiếp theo