Điều kiện ghi cho Quy tắc bảo mật của Cloud Firestore

Hướng dẫn này dựa trên hướng dẫn về cấu trúc quy tắc bảo mật để biết cách thêm điều kiện vào Quy tắc bảo mật của Cloud Firestore. Nếu bạn không phải là thông tin cơ bản về các Quy tắc bảo mật của Cloud Firestore, hãy xem phần bắt đầu của chúng tôi.

Thành phần chính của Quy tắc bảo mật Cloud Firestore là điều kiện. Đáp điều kiện là biểu thức boolean xác định liệu một toán tử cụ thể được phép hoặc bị từ chối. Sử dụng quy tắc bảo mật để ghi các điều kiện kiểm tra xác thực người dùng, xác thực dữ liệu đến hoặc thậm chí truy cập vào các phần khác của cơ sở dữ liệu của bạn.

Xác thực

Một trong những quy tắc bảo mật phổ biến nhất là kiểm soát quyền truy cập dựa trên trạng thái xác thực của người dùng. Ví dụ: ứng dụng của bạn có thể chỉ muốn cho phép người dùng đã đăng nhập để ghi dữ liệu:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to access documents in the "cities" collection
    // only if they are authenticated.
    match /cities/{city} {
      allow read, write: if request.auth != null;
    }
  }
}

Một mô hình phổ biến khác là đảm bảo người dùng chỉ có thể đọc và viết dữ liệu của riêng họ dữ liệu:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure the uid of the requesting user matches name of the user
    // document. The wildcard expression {userId} makes the userId variable
    // available in rules.
    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }
  }
}

Nếu ứng dụng của bạn sử dụng tính năng Xác thực Firebase hoặc Google Cloud Identity Platform, thì biến request.auth chứa thông tin xác thực cho ứng dụng khách yêu cầu dữ liệu. Để biết thêm thông tin về request.auth, hãy xem tài liệu tham khảo tài liệu.

Xác thực dữ liệu

Nhiều ứng dụng lưu trữ thông tin kiểm soát quyền truy cập dưới dạng trường trên các tài liệu trong cơ sở dữ liệu. Quy tắc bảo mật của Cloud Firestore có thể tự động cấp hoặc từ chối cấp quyền truy cập dựa trên tài liệu dữ liệu:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

Biến resource tham chiếu đến tài liệu được yêu cầu, và resource.data là bản đồ tất cả các trường và giá trị được lưu trữ trong tài liệu. Để biết thêm thông tin về biến resource, hãy xem tài liệu tham khảo tài liệu.

Khi ghi dữ liệu, bạn có thể muốn so sánh dữ liệu đến với dữ liệu hiện có. Trong trường hợp này, nếu bộ quy tắc của bạn cho phép thao tác ghi đang chờ xử lý, thì request.resource biến chứa trạng thái tương lai của tài liệu. Đối với các thao tác update chỉ sửa đổi một nhóm nhỏ các trường chứng từ, biến request.resource sẽ chứa trạng thái tài liệu đang chờ xử lý sau thao tác. Bạn có thể kiểm tra trường này trong request.resource để ngăn việc cập nhật dữ liệu không mong muốn hoặc không nhất quán:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure all cities have a positive population and
    // the name is not changed
    match /cities/{city} {
      allow update: if request.resource.data.population > 0
                    && request.resource.data.name == resource.data.name;
    }
  }
}

Truy cập các tài liệu khác

Bằng cách sử dụng các hàm get()exists(), các quy tắc bảo mật của bạn có thể đánh giá các yêu cầu đến đối với các tài liệu khác trong cơ sở dữ liệu. get() và Cả hai hàm exists() đều yêu cầu đường dẫn tài liệu được chỉ định đầy đủ. Khi sử dụng để tạo đường dẫn cho get()exists(). Bạn cần xác định rõ ràng Escape bằng cú pháp $(variable).

Trong ví dụ bên dưới, biến database được trình so khớp thu thập câu lệnh match /databases/{database}/documents và được dùng để tạo đường dẫn:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      // Make sure a 'users' document exists for the requesting user before
      // allowing any writes to the 'cities' collection
      allow create: if request.auth != null && exists(/databases/$(database)/documents/users/$(request.auth.uid));

      // Allow the user to delete cities if their user document has the
      // 'admin' field set to 'true'
      allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
    }
  }
}

Để ghi, bạn có thể dùng hàm getAfter() để truy cập vào trạng thái của một sau khi một giao dịch hoặc một đợt ghi hoàn tất nhưng trước khi giao dịch hoặc cam kết hàng loạt. Giống như get(), hàm getAfter() nhận đường dẫn tài liệu được chỉ định đầy đủ. Bạn có thể dùng getAfter() để xác định các nhóm hoạt động ghi phải diễn ra cùng nhau dưới dạng giao dịch hoặc lô.

Truy cập giới hạn cuộc gọi

Có giới hạn về số lệnh gọi quyền truy cập vào tài liệu trong mỗi lần đánh giá bộ quy tắc:

  • 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 10 trước đó cũng áp dụng cho mỗi hoạt động.

    Ví dụ: giả sử bạn tạo một yêu cầu ghi theo lô có 3 lượt 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 cách ghi sử dụng 2 10 lệnh gọi truy cập và yêu cầu ghi theo lô sử dụng 6 trong số 20 quyền truy cập cuộc gọi.

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ố tài liệu lệnh gọi truy cập 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.

Để được giải thích chi tiết về việc các hạn mức này ảnh hưởng như thế nào đến các giao dịch và ghi hàng loạt, hãy xem hướng dẫn để bảo mật hoạt động nguyên tử.

Truy cập cuộc gọi và giá

Khi dùng các hàm này, bạn sẽ thực thi một thao tác đọc trong cơ sở dữ liệu của mình, điều này có nghĩa là bạn sẽ bị tính phí đọc tài liệu ngay cả khi quy tắc của bạn từ chối yêu cầu. Xem giá của Cloud Firestore để biết thông tin thanh toán cụ thể hơn.

Hàm tuỳ chỉnh

Khi quy tắc bảo mật của bạn trở nên phức tạp hơn, bạn có thể cần gói điều kiện trong các hàm mà bạn có thể sử dụng lại trong bộ quy tắc của mình. Quy tắc bảo mật hỗ trợ các hàm tuỳ chỉnh. Cú pháp cho hàm tuỳ chỉnh hơi giống JavaScript, nhưng các hàm quy tắc bảo mật được viết bằng ngôn ngữ riêng có một số hạn chế quan trọng:

  • Các hàm chỉ có thể chứa một câu lệnh return duy nhất. Họ không thể chứa bất kỳ logic bổ sung nào. Ví dụ: các trình xử lý này không thể thực thi vòng lặp hoặc lệnh gọi các dịch vụ bên ngoài.
  • Hàm có thể tự động truy cập vào các hàm và biến trong phạm vi mà trong đó chúng được xác định. Ví dụ: một hàm được xác định trong phạm vi service cloud.firestore có quyền truy cập vào biến resource cũng như các hàm tích hợp sẵn như get()exists().
  • Các hàm có thể gọi các hàm khác nhưng có thể không lặp lại. Tổng số cuộc gọi chiều sâu ngăn xếp được giới hạn ở 10.
  • Trong phiên bản quy tắc v2, các hàm có thể xác định biến bằng từ khoá let. Hàm có thể có tối đa 10 liên kết let nhưng phải kết thúc bằng lệnh trả về tuyên bố.

Một hàm được định nghĩa bằng từ khoá function và nhận giá trị từ 0 trở lên đối số. Ví dụ: bạn có thể muốn kết hợp hai loại điều kiện được sử dụng trong các ví dụ trên thành một hàm duy nhất:

service cloud.firestore {
  match /databases/{database}/documents {
    // True if the user is signed in or the requested data is 'public'
    function signedInOrPublic() {
      return request.auth.uid != null || resource.data.visibility == 'public';
    }

    match /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

Việc sử dụng các hàm trong quy tắc bảo mật giúp bạn dễ bảo trì hơn khi để quy tắc trở nên phức tạp hơn.

Quy tắc không phải là bộ lọc

Sau khi bạn bảo mật dữ liệu của mình và bắt đầu ghi truy vấn, hãy nhớ rằng việc bảo mật quy tắc không phải là bộ lọc. Bạn không thể viết truy vấn cho tất cả tài liệu trong một thu thập và yêu cầu Cloud Firestore chỉ trả về những tài liệu ứng dụng khách hiện tại có quyền truy cập.

Ví dụ: dùng quy tắc bảo mật sau:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

Bị từ chối: Quy tắc này từ chối cụm từ tìm kiếm sau vì đã đặt kết quả có thể bao gồm tài liệu trong đó visibility không phải là public:

Web
db.collection("cities").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
    });
});

Cho phép: Quy tắc này cho phép truy vấn sau vì mệnh đề where("visibility", "==", "public") đảm bảo rằng tập hợp kết quả đáp ứng điều kiện của quy tắc:

Web
db.collection("cities").where("visibility", "==", "public").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
        });
    });

Các quy tắc bảo mật của Cloud Firestore đánh giá từng truy vấn dựa trên tiềm năng của nó kết quả và không thực hiện được yêu cầu nếu có thể trả về tài liệu mà ứng dụng khách không có quyền đọc. Truy vấn phải tuân theo những ràng buộc được đặt bởi các quy tắc bảo mật của bạn. Để biết thêm thông tin về các quy tắc và truy vấn bảo mật, hãy xem phần bảo mật truy vấn dữ liệu.

Các bước tiếp theo