Tìm hiểu Firestore security rules
Bài đăng này đã không được cập nhật trong 4 năm
Ngày nay việc build một client app(React Js, Vue Js, Android, iOS,...) làm việc trực tiếp với firebase
là rất phổ biến, dễ dàng và nhanh chóng. Từ một app đơn giản cho đến app có business phức tạp, firebase đều có thể đáp ứng được. Vì client app connect trực tiếp đến firebase
nên các vấn đề securities: authentication, authorization, validate data,... luôn được quan tâm hàng đầu.
Thông thường client app thực hiện việc CRUD
thông qua các api, và việc check security được thực hiện ở ngay các api này. Còn đối với app thực hiện CRUD
trực tiếp đến firebase
thì các vấn đề securities sẽ được xử lý thông qua bộ quy tắc security rules.
1. Giới thiệu firebase security rules
Firebase security rules cho phép ai được quyền read, write data trong Cloud Firestore, Realtime Database, và Cloud Storage. Security rules được viết theo cú pháp tương tự javascript dưới dạng cấu trúc JSON.
- .read: mô tả với điều kiện nào thì cho phép user đọc data bao gồm: get, list
- .write: mô tả với điều kiện nào thì cho phép user ghi data bao gồm: create, update, delete
Sau đây chúng ta sẽ cùng tìm hiểu cách viết security rules cho Cloud Firestore, một service lưu trữ data NOSQL, mạnh mẽ, linh động, realtime data phổ biến nhất hiện nay.
2. Cloud firestore rules
Mặc định thì firestore rules sẽ không cho phép bất kỳ user/anonymous nào từ client app có thể truy cập được database. Việc này sẽ bảo vệ database không được truy cập trái phép cho đến khi chúng ta customize lại rules.
Cú pháp:
service cloud.firestore {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
Quy tắc rules được tóm tắt như sau: Firebase sẽ cho phép phương thức (methods
) truy cập data vào những path
cụ thể dựa vào điều kiện(condition
) được định nghĩa sẵn.
3. Một số rules thường dùng
3.1. Cho phép truy cập vào database
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
Cho phép tất cả các truy cập vào collections, subcollections của database
3.2. Chặn tất cả truy cập vào database
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
Chặn tất cả các truy cập vào collections, subcollections của database
3.3. Cho phép truy cập nếu user đã xác thực (Firebase authentication)
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if request.auth != null;
}
}
}
Chỉ cho phép read/write
vào database những user đã login thông qua firebase authentication(Email/password, Phone, Google, Facebook, Twitter, Github, ...)
3.4. Cho phép truy cập data thuộc user đang login
service cloud.firestore {
match /databases/{database}/documents {
// Allow only authenticated content owners access
match /some_collection/{userId}/{documents=**} {
allow read, write: if request.auth != null && request.auth.uid == userId
}
}
}
Đầu tiên chúng ta tạo một collection(some_collection
), dùng userId
để định danh mỗi document trong collection. Rules ở trên chỉ cho phép truy cập vào data thuộc user đang login, không cho phép truy cập vào những data không thuộc user đó thông qua userId
.
3.5. Phân quyền truy cập data
service cloud.firestore {
match /databases/{database}/documents {
// Allow public read access, but only content owners can write
match /some_collection/{document} {
allow read: if true // 1
allow create: if request.auth.uid == request.resource.data.author_uid; // 2
allow update, delete: if request.auth.uid == resource.data.author_uid; // 3
}
match /public_collection/{document=**} {
allow read, write: if true; // 4
}
}
}
- Cho phép
read
public trênsome_collection
- Chỉ cho phép
create
data có fieldauthor_uid
(data chuẩn bị tạo mới) của user đang login - Chỉ cho phép
update/delete
data cóauthor_uid
(data đã tạo trước đó) thuộc user đang login - Cho phép
read/write
public trênpublic_collection
và tất cả subcollections
3.6. Phân quyền truy cập data theo role
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true; // 1
}
// For role-based access, assign specific roles to users
match /some_collection/{document} {
allow read: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Reader" // 2
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Writer" // 3
}
}
}
- Chỉ admin mới có quyền
read/write
trên tất cả collections, dựa vào fieldadmin
của document có id làuserId
của user đang login(documentusers/{userId}
chứa data liên quan đến user được tạo mỗi khi đăng ký mới một user) - Cho phép
read
trênsome_collection
đối với user có role làReader
- Cho phép
write
trênsome_collection
đối với user có role làWriter
3.7. Sử dụng function
service cloud.firestore {
match /databases/{database}/documents {
function isAuthenticated() {
return request.auth.uid != null;
}
function isDeleted() {
return get(/databases/$(database)/documents/users/$(request.auth.uid)).data.deleted_flg == false;
}
match /some_collection/{document} {
allow read, write: if isAuthenticated() && isDeleted()
}
}
}
Cho phép read/write
trên some_collection
nếu user đã login và có deleted_flg = false
4. Kết luận
Lưu ý:
- Nêú có nhiều rules apply cho 1 path thì chỉ cần có 1 rule hợp lệ thì có thể access được data của path đó.
- Rule apply trên
children path
không ảnh hưởng đến rule củaparent path
, tức là nếu set rules choread
ở tất cả các collection và set rule không choread
ởprivate_collection
thì data ởprivate_collection
vẫn có thểread
được.
Trên đây là một số cách viết firestore rules cơ bản, hy vọng mọi người có thể apply vào các projects một cách hợp lý, xin cám ơn.
All rights reserved