Skip to main content

ใส่ Firestore rule

Firestore Security Rule คืออะไร ?

เอกสารต้นฉบับ: https://firebase.google.com/docs/firestore/security/get-started

Firestore Security Rule คือ set ของ configurations ที่ระบุเอาไว้ว่าใครที่สามารถอ่านและเขียนข้อมูลลงได้บ้าง

  • ฉบับ local (หรือ development บนเครื่อง) จะสามารถแก้ผ่าน firestore.rules ที่สร้างจาก firebase init ตรงๆได้
  • ฉบับ server จะสามารถแก้ผ่านหน้าเว็บ Firebase > Firestore > Rules

rule-01

ในหัวข้อนี้เราจะปรับกันที่ local กันก่อน แล้วเดี๋ยวก่อน deployment เราจะทำการย้าย Firestore Security Rule อีกที

กั้นข้อมูล user

โดย เงื่อนไขคือ

  • ดึงได้เฉพาะข้อมูลของ user ตัวเอง (ถ้าไม่ใช่ admin)
  • ไม่เว้นแม้แต่ moderator ก็มาเห็น user คนอื่นไม่ได้ (เมื่อลองมาเปิด path ตรงๆ)
  • ถ้าเป็น admin = สามารถดูข้อมูลทุกคนได้

ที่ firestore.rules

service cloud.firestore {
match /databases/{database}/documents {
function isAdmin() {
return request.auth.uid != null || get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == 'admin';
}

match /users/{userId} {
allow read, write: if request.auth != null && (request.auth.uid == userId || isAdmin());
}
}
}

กั้นข้อมูล Frontend ให้เห็นแค่ status 'open' เท่านั้น

เพิ่มเงื่อนไขนี้เข้ามาใน firestore.rules

rules_version = '2';

service cloud.firestore {
match /databases/{database}/documents {
match /products/{productId} {
allow read: if (request.auth != null && isAdmin()) || (resource.data.status == 'open');
allow write: if (request.auth != null && isAdmin()) || (resource.data.status == 'open');
}
}
}

ทีนี้เราจะเจอว่าหน้าบ้านไม่สามารถเรียกใช้ข้อมูลได้ ให้ปรับการเรียก product ฝั่ง Frontend ใหม่เป็น

ที่ stores/user/product.js

import { defineStore } from 'pinia'

import {
collection,
getDocs,
// เพิ่ม query กับ where เข้ามา
query,
where
} from 'firebase/firestore'

export const useUserProductStore = defineStore('user-product', {
state: () => ({
list: [],
loaded: false,
page: 1,
limit: 2
}),
actions: {
async loadProduct () {
// เพิ่ม where และ query ในการเรียก condition ตาม rule
const productsCol = query(collection(db, 'products'), where('status', '==', 'open'))
const productSnapshop = await getDocs(productsCol)
const productList = productSnapshop.docs.map(doc => doc.data())
if (productList && productList.length > 0) {
this.list = productList
}
this.loaded = true
},
/* function อื่นเหมือนเดิม */
}
})

ผลลัพธ์ของ code นี้ ให้ลอง setup product เป็น status close ดู = จะเจอว่า product ที่เป็น close จะไม่แสดงออกมาได้

rule-02