Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

เงื่อนไขการเขียนสำหรับกฎความปลอดภัยของ Cloud Firestore

จัดทุกอย่างให้เป็นระเบียบอยู่เสมอด้วยคอลเล็กชัน บันทึกและจัดหมวดหมู่เนื้อหาตามค่ากำหนดของคุณ

คู่มือนี้สร้างขึ้นจากคู่มือ กฎความปลอดภัยด้านโครงสร้าง เพื่อแสดงวิธีเพิ่มเงื่อนไขให้กับกฎความปลอดภัยของ Cloud Firestore หากคุณไม่คุ้นเคยกับพื้นฐานของกฎความปลอดภัยของ Cloud Firestore โปรดดูคู่มือ เริ่มต้น ใช้งาน

องค์ประกอบหลักของกฎความปลอดภัยของ Cloud Firestore คือเงื่อนไข เงื่อนไขคือนิพจน์บูลีนที่กำหนดว่าควรอนุญาตหรือปฏิเสธการดำเนินการเฉพาะ ใช้กฎความปลอดภัยในการเขียนเงื่อนไขที่ตรวจสอบการรับรองความถูกต้องของผู้ใช้ ตรวจสอบข้อมูลขาเข้า หรือแม้แต่เข้าถึงส่วนอื่นๆ ของฐานข้อมูลของคุณ

การรับรองความถูกต้อง

รูปแบบกฎความปลอดภัยที่พบมากที่สุดรูปแบบหนึ่งคือการควบคุมการเข้าถึงตามสถานะการรับรองความถูกต้องของผู้ใช้ ตัวอย่างเช่น แอปของคุณอาจต้องการอนุญาตให้เฉพาะผู้ใช้ที่ลงชื่อเข้าใช้เขียนข้อมูล:

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;
    }
  }
}

รูปแบบทั่วไปอีกรูปแบบหนึ่งคือการทำให้แน่ใจว่าผู้ใช้สามารถอ่านและเขียนข้อมูลของตนเองได้เท่านั้น:

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;
    }
  }
}

หากแอปของคุณใช้ Firebase Authentication หรือ Google Cloud Identity Platform ตัวแปร request.auth จะมีข้อมูลการตรวจสอบสิทธิ์สำหรับไคลเอ็นต์ที่ขอข้อมูล สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ request.auth โปรดดู เอกสารอ้างอิง

การตรวจสอบข้อมูล

แอพจำนวนมากเก็บข้อมูลการควบคุมการเข้าถึงเป็นฟิลด์ในเอกสารในฐานข้อมูล กฎความปลอดภัยของ Cloud Firestore สามารถอนุญาตหรือปฏิเสธการเข้าถึงแบบไดนามิกตามข้อมูลเอกสาร:

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';
    }
  }
}

ตัวแปร resource อ้างถึงเอกสารที่ร้องขอ และ resource.data เป็นแผนที่ของฟิลด์และค่าทั้งหมดที่จัดเก็บไว้ในเอกสาร สำหรับข้อมูลเพิ่มเติมเกี่ยวกับตัวแปร resource โปรดดู เอกสารอ้างอิง

เมื่อเขียนข้อมูล คุณอาจต้องการเปรียบเทียบข้อมูลขาเข้ากับข้อมูลที่มีอยู่ ในกรณีนี้ หากชุดกฎของคุณอนุญาตให้มีการเขียนที่รอดำเนินการ ตัวแปร request.resource จะมีสถานะในอนาคตของเอกสาร สำหรับการดำเนินการ update ที่แก้ไขชุดย่อยของฟิลด์เอกสารเท่านั้น ตัวแปร request.resource จะมีสถานะเอกสารที่ค้างอยู่หลังการดำเนินการ คุณสามารถตรวจสอบค่าฟิลด์ใน request.resource เพื่อป้องกันการอัปเดตข้อมูลที่ไม่ต้องการหรือไม่สอดคล้องกัน:

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;
    }
  }
}

เข้าถึงเอกสารอื่นๆ

การใช้ฟังก์ชัน get() และที่ exists() กฎความปลอดภัยของคุณสามารถประเมินคำขอที่เข้ามาเทียบกับเอกสารอื่นๆ ในฐานข้อมูล ฟังก์ชัน get() และที่ exists() ต้องการเส้นทางเอกสารที่ระบุทั้งหมด เมื่อใช้ตัวแปรเพื่อสร้างเส้นทางสำหรับ get() และไม่ exists() คุณต้องหลีกเลี่ยงตัวแปรอย่างชัดเจนโดยใช้ไวยากรณ์ $(variable)

ในตัวอย่างด้านล่าง ตัวแปร database ถูกจับโดยคำสั่ง match /databases/{database}/documents และใช้เพื่อสร้างเส้นทาง:

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
    }
  }
}

สำหรับการเขียน คุณสามารถใช้ getAfter() เพื่อเข้าถึงสถานะของเอกสารหลังจากการทำธุรกรรมหรือชุดของการเขียนเสร็จสมบูรณ์ แต่ก่อนการทำธุรกรรมหรือชุดการกระทำ เช่นเดียวกับ get() getAfter() ใช้เส้นทางเอกสารที่ระบุทั้งหมด คุณสามารถใช้ getAfter() เพื่อกำหนดชุดของการเขียนที่ต้องดำเนินการร่วมกันเป็นธุรกรรมหรือเป็นชุด

เข้าถึงขีด จำกัด การโทร

มีข้อจำกัดในการเรียกใช้การเข้าถึงเอกสารต่อการประเมินชุดกฎ:

  • 10 สำหรับคำขอเอกสารเดี่ยวและคำขอเคียวรี
  • 20 สำหรับการอ่านหลายเอกสาร ธุรกรรม และการเขียนเป็นชุด ขีดจำกัด 10 ก่อนหน้านี้ใช้กับการดำเนินการแต่ละครั้งด้วย

    ตัวอย่างเช่น สมมติว่าคุณสร้างคำขอเขียนแบบกลุ่มที่มีการดำเนินการเขียน 3 ครั้ง และกฎความปลอดภัยของคุณใช้การเรียกใช้การเข้าถึงเอกสาร 2 ครั้งเพื่อตรวจสอบความถูกต้องของการเขียนแต่ละครั้ง ในกรณีนี้ การเขียนแต่ละครั้งใช้การเรียกใช้การเข้าถึง 2 จาก 10 ครั้ง และคำขอเขียนแบบแบทช์ใช้การเรียกใช้การเข้าถึง 6 จาก 20 ครั้ง

เกินขีด จำกัด ส่งผลให้เกิดข้อผิดพลาดในการอนุญาตการปฏิเสธ การเรียกใช้การเข้าถึงเอกสารบางรายการอาจถูกแคช และการเรียกที่แคชจะไม่นับรวมในขีดจำกัด

สำหรับคำอธิบายโดยละเอียดเกี่ยวกับผลกระทบของข้อจำกัดเหล่านี้ต่อธุรกรรมและการเขียนเป็นชุด โปรดดูคู่มือสำหรับ การดำเนินการเกี่ยวกับความปลอดภัยในระดับปรมาณู

เข้าถึงการโทรและการกำหนดราคา

การใช้ฟังก์ชันเหล่านี้ดำเนินการอ่านในฐานข้อมูลของคุณ ซึ่งหมายความว่าคุณจะถูกเรียกเก็บเงินสำหรับการอ่านเอกสารแม้ว่ากฎของคุณจะปฏิเสธคำขอก็ตาม ดู ราคา Cloud Firestore สำหรับข้อมูลการเรียกเก็บเงินที่เฉพาะเจาะจงมากขึ้น

ฟังก์ชั่นที่กำหนดเอง

เมื่อกฎความปลอดภัยของคุณซับซ้อนมากขึ้น คุณอาจต้องการรวมชุดเงื่อนไขในฟังก์ชันที่คุณใช้ซ้ำได้ในชุดกฎของคุณ กฎความปลอดภัยรองรับฟังก์ชันแบบกำหนดเอง ไวยากรณ์สำหรับฟังก์ชันแบบกำหนดเองจะคล้ายกับ JavaScript แต่ฟังก์ชันกฎความปลอดภัยเขียนด้วยภาษาเฉพาะโดเมนซึ่งมีข้อจำกัดที่สำคัญบางประการ:

  • ฟังก์ชันสามารถมีคำสั่ง return เดียวเท่านั้น ไม่สามารถมีตรรกะเพิ่มเติมใดๆ ตัวอย่างเช่น พวกเขาไม่สามารถดำเนินการวนซ้ำหรือเรียกใช้บริการภายนอกได้
  • ฟังก์ชันสามารถเข้าถึงฟังก์ชันและตัวแปรโดยอัตโนมัติจากขอบเขตที่กำหนดไว้ ตัวอย่างเช่น ฟังก์ชันที่กำหนดภายในขอบเขต service cloud.firestore มีสิทธิ์เข้าถึงตัวแปร resource และฟังก์ชันในตัว เช่น get() และ exist exists()
  • ฟังก์ชันอาจเรียกใช้ฟังก์ชันอื่นแต่ไม่สามารถเรียกซ้ำได้ ความลึกของ call stack ทั้งหมดจำกัดอยู่ที่ 10
  • ในกฎเวอร์ชัน v2 ฟังก์ชันสามารถกำหนดตัวแปรโดยใช้คำหลัก let ฟังก์ชันสามารถมีได้มากถึง 10 การรวม let แต่ต้องลงท้ายด้วยคำสั่ง return

ฟังก์ชันถูกกำหนดด้วยคีย์เวิร์ดของ function และรับอาร์กิวเมนต์เป็นศูนย์หรือมากกว่านั้น ตัวอย่างเช่น คุณอาจต้องการรวมเงื่อนไขสองประเภทที่ใช้ในตัวอย่างด้านบนเป็นฟังก์ชันเดียว:

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();
    }
  }
}

การใช้ฟังก์ชันในกฎความปลอดภัยทำให้รักษาได้มากขึ้นตามความซับซ้อนของกฎที่เพิ่มขึ้น

กฎไม่ใช่ตัวกรอง

เมื่อคุณรักษาความปลอดภัยของข้อมูลและเริ่มเขียนแบบสอบถามแล้ว โปรดทราบว่ากฎความปลอดภัยไม่ใช่ตัวกรอง คุณไม่สามารถเขียนแบบสอบถามสำหรับเอกสารทั้งหมดในคอลเลกชั่น และคาดว่า Cloud Firestore จะส่งคืนเฉพาะเอกสารที่ไคลเอนต์ปัจจุบันมีสิทธิ์เข้าถึง

ตัวอย่างเช่น ใช้กฎความปลอดภัยต่อไปนี้:

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';
    }
  }
}

ปฏิเสธ : กฎนี้ปฏิเสธการสืบค้นต่อไปนี้ เนื่องจากชุดผลลัพธ์สามารถรวมเอกสารที่ visibility ไม่ public :

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

Allowed : กฎนี้อนุญาตการสืบค้นต่อไปนี้เนื่องจากคำสั่ง where("visibility", "==", "public") รับประกันว่าชุดผลลัพธ์ตรงตามเงื่อนไขของกฎ:

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

กฎความปลอดภัยของ Cloud Firestore จะประเมินการสืบค้นแต่ละรายการเทียบกับผลลัพธ์ที่เป็นไปได้ และดำเนินการตามคำขอหากสามารถส่งคืนเอกสารที่ไคลเอนต์ไม่มีสิทธิ์อ่าน ข้อความค้นหาต้องเป็นไปตามข้อจำกัดที่กำหนดโดยกฎความปลอดภัยของคุณ สำหรับข้อมูลเพิ่มเติมเกี่ยวกับกฎความปลอดภัยและการสืบค้น โปรดดู ที่ การสืบค้นข้อมูลอย่างปลอดภัย

ขั้นตอนถัดไป