Xác thực
Một trong những tình huống phổ biến nhất là cho phép truy cập dữ liệu nếu user đã đăng nhập (còn gọi là xác thực, authentication).
service cloud.firestore {
match /databases/{database}/documents {
// Cho phép user truy cập document
// trong collection cities nếu đã đăng nhập
match /cities/{city} {
allow read, write: if request.auth.uid != null;
}
}
}
Hoặc một tình huống phổ biến thứ 2 là cho phép user read và write lên dữ liệu của chính user đó
services cloud.firestore {
match /databases/{database}/documents {
// chỉ cho phép uid khớp với userId trong document.
// Dùng ký tự đại diện {userId} như một biến bên trong câu điều kiện
match /users/{userId} {
allow read, update, delete: if request.auth.uid == userId;
allow create: if request.auth.uid != null;
}
}
}
Nếu đang sử dụng Firebase Authentication, biến request.auth
sẽ chưa thông tin của user gởi request, xem thêm chi tiết ở đây.
Kiểm tra dữ liệu
Nếu muốn can thiệp việc cho phép hoặc từ chối truy cập theo dữ liệu trong document
service cloud.firestore {
match /databases/{database}/documents {
// cho phép truy cập nếu giá trị của visibility bằng public
match /cities/{city} {
allow read: if resource.data.visibility == 'public';
}
}
}
Biến resource
tương ứng với dữ liệu của document đang request, request.data
sẽ là toàn bộ các field lưu trong document
Trước khi write dữ liệu xuống, chúng ta sẽ muốn kiểm tra dữ liệu đang có và dữ liệu mới. Nếu chúng ta đang set rule pending write (không write dữ liệu ngay lập tức mà đợi xí), biến request.resource
lúc này sẽ chứa dữ liệu mới.
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
allow update: if request.resource.data.population > 0
&& request.resource.data.name == resource.data.name
}
}
}
Truy cập đến các documents khác
Sử dụng get()
và exists()
chúng ta có thể đánh giá các request với các documents trong database. Cả hai hàm này đều yêu cầu chỉ định đường dẫn đầy đủ, và phải đưa biến theo cú pháp $(biến)
trong đường dẫn
service cloud.firestore {
match /databases/{database}/documents {
match /cities/{city} {
// kiểm tra user hiện tại
// có tồn tại bên trong collections users
// trước khi cho phép tạo thêm city mới
allow create: if exists(/databases/$(database)/documents/users/$(request.auth.uid))
// cho phép user xóa city nếu user này là admin
allow delete: if get(/databases/$(database)/documents/users/$(request.auth.id).data.admin == true)
}
}
}
Đối với thao tác write, chúng ta có thể sử dụng getAfter()
để truy cập dữ liệu của document sau khi thực hiện, thằng này cũng giống như get
phải dùng đường dẫn đầy đủ.
Hàm tùy biến
Một khi các rule security này trở nên phức tạp, chúng ta sẽ muốn gom các điều kiện này vào trong một hàm để tái sử dụng. Firestore hỗ trợ luôn. Nó sẽ như Javascript, tuy nhiên không hẳn là javascript đâu, nó có một số hạn chế
- Hàm này luôn chỉ chứa 1 return, không chạy loop, gọi service bên ngoài
- Hàm có thể access được các hàm và biến có cùng scope.
- Hàm có thể gọi đến hàm khác nhưng không được recurse, tối đa là sâu đến 10 thôi.
Ví dụ kết hợp cả 2 điều kiện ở trên thành một hàm
service cloud.firestore {
match /databases/{database}/documents {
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();
}
}
}
Initializing...