คู่มือนี้สร้างขึ้นจากคู่มือ ภาษาหลักสำหรับเรียนรู้กฎความปลอดภัย Firebase เพื่อแสดงวิธีเพิ่มเงื่อนไขในกฎความปลอดภัยของฐานข้อมูลเรียลไทม์ของ Firebase
โครงสร้างหลักของกฎการรักษาความปลอดภัยฐานข้อมูลเรียลไทม์คือ เงื่อนไข เงื่อนไขคือนิพจน์บูลีนที่กำหนดว่าการดำเนินการเฉพาะควรได้รับอนุญาตหรือปฏิเสธ สำหรับกฎพื้นฐาน การใช้สัญพจน์ true
และ false
เป็นเงื่อนไขที่ใช้ได้ผลดีกับนายอำเภอ แต่ภาษากฎความปลอดภัยของฐานข้อมูลเรียลไทม์ช่วยให้คุณมีวิธีเขียนเงื่อนไขที่ซับซ้อนมากขึ้นซึ่งสามารถ:
- ตรวจสอบการพิสูจน์ตัวตนผู้ใช้
- ประเมินข้อมูลที่มีอยู่กับข้อมูลที่ส่งใหม่
- เข้าถึงและเปรียบเทียบส่วนต่างๆ ของฐานข้อมูลของคุณ
- ตรวจสอบข้อมูลขาเข้า
- ใช้โครงสร้างของคิวรีขาเข้าสำหรับลอจิกความปลอดภัย
การใช้ตัวแปร $ เพื่อจับกลุ่มเส้นทาง
คุณสามารถจับภาพบางส่วนของเส้นทางสำหรับการอ่านหรือเขียนโดยการประกาศตัวแปรการจับภาพด้วย $
นำหน้า สิ่งนี้ทำหน้าที่เป็นไวด์การ์ดและเก็บค่าของคีย์นั้นเพื่อใช้ภายในเงื่อนไขของกฎ:
{ "rules": { "rooms": { // this rule applies to any child of /rooms/, the key for each room id // is stored inside $room_id variable for reference "$room_id": { "topic": { // the room's topic can be changed if the room id has "public" in it ".write": "$room_id.contains('public')" } } } } }
ตัวแปรไดนามิก $
สามารถใช้ควบคู่ไปกับชื่อพาธคงที่ ในตัวอย่างนี้ เรากำลังใช้ตัวแปร $other
เพื่อประกาศ กฎ .validate
ที่รับรองว่า widget
ไม่มีลูกอื่นนอกจาก title
และ color
การเขียนใด ๆ ที่จะส่งผลให้มีการสร้างลูกเพิ่มเติมจะล้มเหลว
{ "rules": { "widget": { // a widget can have a title or color attribute "title": { ".validate": true }, "color": { ".validate": true }, // but no other child paths are allowed // in this case, $other means any key excluding "title" and "color" "$other": { ".validate": false } } } }
การตรวจสอบสิทธิ์
รูปแบบกฎความปลอดภัยที่พบบ่อยที่สุดรูปแบบหนึ่งคือการควบคุมการเข้าถึงตามสถานะการตรวจสอบสิทธิ์ของผู้ใช้ ตัวอย่างเช่น แอปของคุณอาจต้องการให้ผู้ใช้ที่ลงชื่อเข้าใช้เท่านั้นเขียนข้อมูลได้
หากแอปของคุณใช้การตรวจสอบสิทธิ์ Firebase ตัวแปร request.auth
จะมีข้อมูลการตรวจสอบสิทธิ์สำหรับไคลเอ็นต์ที่ขอข้อมูล สำหรับข้อมูลเพิ่มเติมเกี่ยวกับ request.auth
โปรดดู เอกสารอ้างอิง
การตรวจสอบสิทธิ์ของ Firebase ผสานรวมกับฐานข้อมูลเรียลไทม์ของ Firebase เพื่อให้คุณควบคุมการเข้าถึงข้อมูลแบบรายผู้ใช้ได้โดยใช้เงื่อนไข เมื่อผู้ใช้ตรวจสอบ auth
แล้ว ตัวแปรตรวจสอบสิทธิ์ในกฎกฎความปลอดภัยของฐานข้อมูลเรียลไทม์จะถูกเติมด้วยข้อมูลของผู้ใช้ ข้อมูลนี้รวมถึงตัวระบุที่ไม่ซ้ำกัน ( uid
) เช่นเดียวกับข้อมูลบัญชีที่เชื่อมโยง เช่น ID Facebook หรือที่อยู่อีเมล และข้อมูลอื่นๆ หากคุณใช้ผู้ให้บริการตรวจสอบสิทธิ์แบบกำหนดเอง คุณสามารถเพิ่มฟิลด์ของคุณเองลงในเพย์โหลดการตรวจสอบสิทธิ์ของผู้ใช้ได้
ส่วนนี้อธิบายวิธีรวมภาษากฎความปลอดภัยของฐานข้อมูลเรียลไทม์ของ Firebase กับข้อมูลการตรวจสอบสิทธิ์เกี่ยวกับผู้ใช้ของคุณ เมื่อรวมแนวคิดทั้งสองนี้เข้าด้วยกัน คุณจะสามารถควบคุมการเข้าถึงข้อมูลตามข้อมูลประจำตัวของผู้ใช้ได้
auth
ตรวจสอบสิทธิ์
ตัวแปรตรวจสอบ auth
ที่กำหนดไว้ล่วงหน้าในกฎนั้นเป็นโมฆะก่อนที่จะมีการตรวจสอบสิทธิ์
เมื่อผู้ใช้ได้รับการตรวจสอบสิทธิ์ด้วย Firebase Authentication แล้ว จะมีแอตทริบิวต์ต่อไปนี้:
ผู้ให้บริการ | วิธีการตรวจสอบสิทธิ์ที่ใช้ ("รหัสผ่าน", "ไม่ระบุชื่อ", "facebook", "github", "google" หรือ "twitter") |
uid | ID ผู้ใช้ที่ไม่ซ้ำ รับประกันว่าจะไม่ซ้ำกันในทุกผู้ให้บริการ |
โทเค็น | เนื้อหาของโทเค็น Firebase Auth ID ดูเอกสารอ้างอิงสำหรับ auth.token สำหรับรายละเอียดเพิ่มเติม |
นี่คือตัวอย่างกฎที่ใช้ตัวแปร auth
เพื่อให้แน่ใจว่าผู้ใช้แต่ละรายสามารถเขียนไปยังพาธเฉพาะผู้ใช้เท่านั้น:
{ "rules": { "users": { "$user_id": { // grants write access to the owner of this user account // whose uid must exactly match the key ($user_id) ".write": "$user_id === auth.uid" } } } }
การจัดโครงสร้างฐานข้อมูลของคุณเพื่อรองรับเงื่อนไขการตรวจสอบสิทธิ์
มักจะเป็นประโยชน์ในการจัดโครงสร้างฐานข้อมูลของคุณในลักษณะที่ทำให้การเขียนกฎง่ายขึ้น รูปแบบทั่วไปอย่างหนึ่งสำหรับการจัดเก็บข้อมูลผู้ใช้ใน Realtime Database คือการจัดเก็บผู้ใช้ทั้งหมดของคุณในโหนด users
เดียวซึ่งมีลูกเป็นค่า uid
สำหรับผู้ใช้ทุกคน หากคุณต้องการจำกัดการเข้าถึงข้อมูลนี้โดยให้เฉพาะผู้ใช้ที่เข้าสู่ระบบเท่านั้นที่สามารถดูข้อมูลของตนเองได้ กฎของคุณจะมีลักษณะดังนี้
{ "rules": { "users": { "$uid": { ".read": "auth != null && auth.uid == $uid" } } } }
การทำงานกับการอ้างสิทธิ์ที่กำหนดเองการตรวจสอบสิทธิ์
สำหรับแอปที่ต้องการการควบคุมการเข้าถึงแบบกำหนดเองสำหรับผู้ใช้ที่แตกต่างกัน การตรวจสอบสิทธิ์ Firebase ช่วยให้นักพัฒนาสามารถ ตั้งค่าการอ้างสิทธิ์ในผู้ใช้ Firebase การอ้างสิทธิ์เหล่านี้สามารถเข้าถึงได้ในตัวแปร auth.token
ในกฎของคุณ ต่อไปนี้คือตัวอย่างกฎที่ใช้การอ้างสิทธิ์ที่กำหนดเอง hasEmergencyTowel
:
{ "rules": { "frood": { // A towel is about the most massively useful thing an interstellar // hitchhiker can have ".read": "auth.token.hasEmergencyTowel === true" } } }
นักพัฒนาที่สร้าง โทเค็นการพิสูจน์ตัวตนแบบกำหนดเอง สามารถเพิ่มการอ้างสิทธิ์ในโทเค็นเหล่านี้ได้ การอ้างสิทธิ์เหล่านี้มีอยู่ในตัวแปร auth.token
ในกฎของคุณ
ข้อมูลที่มีอยู่กับข้อมูลใหม่
ตัวแปร data
กำหนดไว้ล่วงหน้าใช้เพื่ออ้างถึงข้อมูลก่อนที่จะดำเนินการเขียน ในทางกลับกัน ตัวแปร newData
มีข้อมูลใหม่ที่จะมีขึ้นหากการดำเนินการเขียนสำเร็จ newData
แสดงผลการรวมของข้อมูลใหม่ที่กำลังเขียนและข้อมูลที่มีอยู่
เพื่อแสดงให้เห็น กฎนี้จะอนุญาตให้เราสร้างเรกคอร์ดใหม่หรือลบเรกคอร์ดที่มีอยู่ แต่ไม่สามารถเปลี่ยนแปลงข้อมูลที่ไม่ใช่ค่าว่างที่มีอยู่ได้:
// we can write as long as old data or new data does not exist // in other words, if this is a delete or a create, but not an update ".write": "!data.exists() || !newData.exists()"
การอ้างอิงข้อมูลในเส้นทางอื่น
ข้อมูลใดๆ สามารถใช้เป็นเกณฑ์สำหรับกฎได้ การใช้ตัวแปรที่กำหนดไว้ล่วงหน้า root
, data
และ newData
เราสามารถเข้าถึงเส้นทางใดก็ได้ตามที่มีอยู่ก่อนหรือหลังเหตุการณ์การเขียน
พิจารณาตัวอย่างนี้ ซึ่งอนุญาตให้ดำเนินการเขียนตราบใดที่ค่าของโหนด /allow_writes/
เป็น true
โหนดหลักไม่มีชุดแฟล็ก readOnly
และมีชื่อ foo
ในข้อมูลที่เขียนใหม่:
".write": "root.child('allow_writes').val() === true && !data.parent().child('readOnly').exists() && newData.child('foo').exists()"
กำลังตรวจสอบข้อมูล
การบังคับใช้โครงสร้างข้อมูลและการตรวจสอบความถูกต้องของรูปแบบและเนื้อหาของข้อมูลควรทำโดยใช้กฎ .validate
ซึ่งจะเรียกใช้หลังจากกฎ .write
อนุญาตการเข้าถึงได้สำเร็จเท่านั้น ด้านล่างนี้คือตัวอย่างคำจำกัดความกฎ .validate
ซึ่งอนุญาตเฉพาะวันที่ในรูปแบบ YYYY-MM-DD ระหว่างปี 1900-2099 ซึ่งตรวจสอบโดยใช้นิพจน์ทั่วไป
".validate": "newData.isString() && newData.val().matches(/^(19|20)[0-9][0-9][-\\/. ](0[1-9]|1[012])[-\\/. ](0[1-9]|[12][0-9]|3[01])$/)"
กฎ .validate
เป็นกฎความปลอดภัยประเภทเดียวที่ไม่ต่อเรียงกัน ถ้ากฎการตรวจสอบใด ๆ ล้มเหลวในเร็กคอร์ดย่อย การดำเนินการเขียนทั้งหมดจะถูกปฏิเสธ นอกจากนี้ คำจำกัดความการตรวจสอบความถูกต้องจะถูกละเว้นเมื่อข้อมูลถูกลบ (นั่นคือ เมื่อค่าใหม่ถูกเขียนเป็น null
)
สิ่งเหล่านี้อาจดูเหมือนเป็นเรื่องเล็กน้อย แต่จริงๆ แล้วเป็นคุณสมบัติที่สำคัญสำหรับการเขียนกฎความปลอดภัยของฐานข้อมูลแบบเรียลไทม์ของ Firebase Realtime พิจารณากฎต่อไปนี้:
{ "rules": { // write is allowed for all paths ".write": true, "widget": { // a valid widget must have attributes "color" and "size" // allows deleting widgets (since .validate is not applied to delete rules) ".validate": "newData.hasChildren(['color', 'size'])", "size": { // the value of "size" must be a number between 0 and 99 ".validate": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 99" }, "color": { // the value of "color" must exist as a key in our mythical // /valid_colors/ index ".validate": "root.child('valid_colors/' + newData.val()).exists()" } } } }
เมื่อคำนึงถึงตัวแปรนี้ ให้ดูผลลัพธ์สำหรับการดำเนินการเขียนต่อไปนี้:
JavaScript
var ref = db.ref("/widget"); // PERMISSION_DENIED: does not have children color and size ref.set('foo'); // PERMISSION DENIED: does not have child color ref.set({size: 22}); // PERMISSION_DENIED: size is not a number ref.set({ size: 'foo', color: 'red' }); // SUCCESS (assuming 'blue' appears in our colors list) ref.set({ size: 21, color: 'blue'}); // If the record already exists and has a color, this will // succeed, otherwise it will fail since newData.hasChildren(['color', 'size']) // will fail to validate ref.child('size').set(99);
วัตถุประสงค์-C
FIRDatabaseReference *ref = [[[FIRDatabase database] reference] child: @"widget"]; // PERMISSION_DENIED: does not have children color and size [ref setValue: @"foo"]; // PERMISSION DENIED: does not have child color [ref setValue: @{ @"size": @"foo" }]; // PERMISSION_DENIED: size is not a number [ref setValue: @{ @"size": @"foo", @"color": @"red" }]; // SUCCESS (assuming 'blue' appears in our colors list) [ref setValue: @{ @"size": @21, @"color": @"blue" }]; // If the record already exists and has a color, this will // succeed, otherwise it will fail since newData.hasChildren(['color', 'size']) // will fail to validate [[ref child:@"size"] setValue: @99];
Swift
var ref = FIRDatabase.database().reference().child("widget") // PERMISSION_DENIED: does not have children color and size ref.setValue("foo") // PERMISSION DENIED: does not have child color ref.setValue(["size": "foo"]) // PERMISSION_DENIED: size is not a number ref.setValue(["size": "foo", "color": "red"]) // SUCCESS (assuming 'blue' appears in our colors list) ref.setValue(["size": 21, "color": "blue"]) // If the record already exists and has a color, this will // succeed, otherwise it will fail since newData.hasChildren(['color', 'size']) // will fail to validate ref.child("size").setValue(99);
Java
FirebaseDatabase database = FirebaseDatabase.getInstance(); DatabaseReference ref = database.getReference("widget"); // PERMISSION_DENIED: does not have children color and size ref.setValue("foo"); // PERMISSION DENIED: does not have child color ref.child("size").setValue(22); // PERMISSION_DENIED: size is not a number Map<String,Object> map = new HashMap<String, Object>(); map.put("size","foo"); map.put("color","red"); ref.setValue(map); // SUCCESS (assuming 'blue' appears in our colors list) map = new HashMap<String, Object>(); map.put("size", 21); map.put("color","blue"); ref.setValue(map); // If the record already exists and has a color, this will // succeed, otherwise it will fail since newData.hasChildren(['color', 'size']) // will fail to validate ref.child("size").setValue(99);
พักผ่อน
# PERMISSION_DENIED: does not have children color and size curl -X PUT -d 'foo' \ https://docs-examples.firebaseio.com/rest/securing-data/example.json # PERMISSION DENIED: does not have child color curl -X PUT -d '{"size": 22}' \ https://docs-examples.firebaseio.com/rest/securing-data/example.json # PERMISSION_DENIED: size is not a number curl -X PUT -d '{"size": "foo", "color": "red"}' \ https://docs-examples.firebaseio.com/rest/securing-data/example.json # SUCCESS (assuming 'blue' appears in our colors list) curl -X PUT -d '{"size": 21, "color": "blue"}' \ https://docs-examples.firebaseio.com/rest/securing-data/example.json # If the record already exists and has a color, this will # succeed, otherwise it will fail since newData.hasChildren(['color', 'size']) # will fail to validate curl -X PUT -d '99' \ https://docs-examples.firebaseio.com/rest/securing-data/example/size.json
ทีนี้มาดูโครงสร้างเดียวกันกัน แต่ใช้ .write
rule แทน .validate
:
{ "rules": { // this variant will NOT allow deleting records (since .write would be disallowed) "widget": { // a widget must have 'color' and 'size' in order to be written to this path ".write": "newData.hasChildren(['color', 'size'])", "size": { // the value of "size" must be a number between 0 and 99, ONLY IF WE WRITE DIRECTLY TO SIZE ".write": "newData.isNumber() && newData.val() >= 0 && newData.val() <= 99" }, "color": { // the value of "color" must exist as a key in our mythical valid_colors/ index // BUT ONLY IF WE WRITE DIRECTLY TO COLOR ".write": "root.child('valid_colors/'+newData.val()).exists()" } } } }
ในตัวแปรนี้ การดำเนินการใดๆ ต่อไปนี้จะสำเร็จ:
JavaScript
var ref = new Firebase(URL + "/widget"); // ALLOWED? Even though size is invalid, widget has children color and size, // so write is allowed and the .write rule under color is ignored ref.set({size: 99999, color: 'red'}); // ALLOWED? Works even if widget does not exist, allowing us to create a widget // which is invalid and does not have a valid color. // (allowed by the write rule under "color") ref.child('size').set(99);
วัตถุประสงค์-C
Firebase *ref = [[Firebase alloc] initWithUrl:URL]; // ALLOWED? Even though size is invalid, widget has children color and size, // so write is allowed and the .write rule under color is ignored [ref setValue: @{ @"size": @9999, @"color": @"red" }]; // ALLOWED? Works even if widget does not exist, allowing us to create a widget // which is invalid and does not have a valid color. // (allowed by the write rule under "color") [[ref childByAppendingPath:@"size"] setValue: @99];
Swift
var ref = Firebase(url:URL) // ALLOWED? Even though size is invalid, widget has children color and size, // so write is allowed and the .write rule under color is ignored ref.setValue(["size": 9999, "color": "red"]) // ALLOWED? Works even if widget does not exist, allowing us to create a widget // which is invalid and does not have a valid color. // (allowed by the write rule under "color") ref.childByAppendingPath("size").setValue(99)
Java
Firebase ref = new Firebase(URL + "/widget"); // ALLOWED? Even though size is invalid, widget has children color and size, // so write is allowed and the .write rule under color is ignored Map<String,Object> map = new HashMap<String, Object>(); map.put("size", 99999); map.put("color", "red"); ref.setValue(map); // ALLOWED? Works even if widget does not exist, allowing us to create a widget // which is invalid and does not have a valid color. // (allowed by the write rule under "color") ref.child("size").setValue(99);
พักผ่อน
# ALLOWED? Even though size is invalid, widget has children color and size, # so write is allowed and the .write rule under color is ignored curl -X PUT -d '{size: 99999, color: "red"}' \ https://docs-examples.firebaseio.com/rest/securing-data/example.json # ALLOWED? Works even if widget does not exist, allowing us to create a widget # which is invalid and does not have a valid color. # (allowed by the write rule under "color") curl -X PUT -d '99' \ https://docs-examples.firebaseio.com/rest/securing-data/example/size.json
สิ่งนี้แสดงให้เห็นความแตกต่างระหว่างกฎ . .write
และ . .validate
ตามที่แสดงให้เห็น กฎเหล่านี้ทั้งหมดควรเขียนโดยใช้ .validate
โดยมีข้อยกเว้นที่เป็นไปได้ของกฎ newData.hasChildren()
ซึ่งจะขึ้นอยู่กับว่าควรอนุญาตให้ลบหรือไม่
กฎตามแบบสอบถาม
แม้ว่าคุณ จะไม่สามารถใช้กฎเป็นตัวกรอง แต่คุณสามารถจำกัดการเข้าถึงชุดย่อยของข้อมูลได้โดยใช้พารามิเตอร์การค้นหาในกฎของคุณ ใช้ query.
นิพจน์ในกฎของคุณเพื่อให้สิทธิ์การเข้าถึงแบบอ่านหรือเขียนตามพารามิเตอร์การสืบค้น
ตัวอย่างเช่น กฎตามคิวรีต่อไปนี้ใช้กฎ ความปลอดภัยตามผู้ใช้และกฎ ตามคิวรีเพื่อจำกัดการเข้าถึงข้อมูลในคอลเลกชั่น baskets
สินค้าเฉพาะในตะกร้าสินค้าที่ผู้ใช้ที่ใช้งานอยู่เป็นเจ้าของ:
"baskets": {
".read": "auth.uid != null &&
query.orderByChild == 'owner' &&
query.equalTo == auth.uid" // restrict basket access to owner of basket
}
แบบสอบถามต่อไปนี้ ซึ่งรวมถึงพารามิเตอร์แบบสอบถามในกฎ จะสำเร็จ:
db.ref("baskets").orderByChild("owner")
.equalTo(auth.currentUser.uid)
.on("value", cb) // Would succeed
อย่างไรก็ตาม แบบสอบถามที่ไม่มีพารามิเตอร์ในกฎจะล้มเหลวโดยมีข้อผิดพลาด PermissionDenied
:
db.ref("baskets").on("value", cb) // Would fail with PermissionDenied
คุณยังสามารถใช้กฎที่ยึดตามคิวรีเพื่อจำกัดจำนวนข้อมูลที่ไคลเอ็นต์ดาวน์โหลดผ่านการดำเนินการอ่าน
ตัวอย่างเช่น กฎต่อไปนี้จำกัดการเข้าถึงเพื่ออ่านผลลัพธ์ 1,000 รายการแรกของการสืบค้น ตามลำดับความสำคัญ:
messages: {
".read": "query.orderByKey &&
query.limitToFirst <= 1000"
}
// Example queries:
db.ref("messages").on("value", cb) // Would fail with PermissionDenied
db.ref("messages").limitToFirst(1000)
.on("value", cb) // Would succeed (default order by key)
query.
ต่อไปนี้ นิพจน์มีอยู่ในกฎความปลอดภัยของฐานข้อมูลเรียลไทม์
นิพจน์กฎตามคิวรี | ||
---|---|---|
การแสดงออก | พิมพ์ | คำอธิบาย |
query.orderByKey query.orderByPriority query.orderByValue | บูลีน | True สำหรับการค้นหาที่เรียงลำดับตามคีย์ ลำดับความสำคัญ หรือค่า เท็จเป็นอย่างอื่น |
query.orderByChild | สตริง โมฆะ | ใช้สตริงเพื่อแสดงเส้นทางสัมพันธ์กับโหนดย่อย ตัวอย่างเช่น query.orderByChild == "address/zip" ถ้าการสืบค้นไม่ได้เรียงลำดับโดยโหนดย่อย ค่านี้เป็นค่าว่าง |
query.startAt query.endAt query.equalTo | สตริง ตัวเลข บูลีน โมฆะ | ดึงขอบเขตของคิวรีที่กำลังดำเนินการ หรือคืนค่า null หากไม่มีชุดที่ถูกผูกไว้ |
query.limitToFirst query.limitToLast | ตัวเลข โมฆะ | ดึงขีดจำกัดในการเรียกใช้คิวรี หรือส่งกลับค่า null ถ้าไม่ได้ตั้งค่าขีดจำกัดไว้ |
ขั้นตอนถัดไป
หลังจากการหารือเกี่ยวกับเงื่อนไขนี้ คุณมีความเข้าใจกฎเกณฑ์ที่ซับซ้อนมากขึ้นและพร้อมที่จะ:
เรียนรู้วิธีจัดการกับกรณีการใช้งานหลัก และเรียนรู้เวิร์กโฟลว์สำหรับการพัฒนา ทดสอบ และปรับใช้กฎ:
- เรียนรู้เกี่ยวกับชุด ตัวแปรกฎที่กำหนดไว้ล่วงหน้าฉบับสมบูรณ์ซึ่งคุณสามารถใช้สร้างเงื่อนไข ได้
- เขียนกฎที่กล่าวถึง สถานการณ์ทั่วไป
- สร้างจากความรู้ของคุณโดยทบทวนสถานการณ์ที่คุณต้อง สังเกตและหลีกเลี่ยงกฎที่ไม่ปลอดภัย
- เรียนรู้เกี่ยวกับ Firebase Local Emulator Suite และวิธีที่คุณสามารถใช้เพื่อ ทดสอบกฎ
- ตรวจสอบวิธีการที่ใช้ได้สำหรับการ ปรับใช้กฎ
เรียนรู้คุณสมบัติกฎที่เจาะจงสำหรับฐานข้อมูลเรียลไทม์:
- เรียนรู้วิธีจัดทำ ดัชนีฐานข้อมูลเรียลไทม์ของคุณ
- ตรวจสอบ REST API สำหรับการปรับใช้ Rules