Firebase Security Rules cho phép bạn kiểm soát quyền truy cập vào dữ liệu đã lưu trữ. Cú pháp quy tắc linh hoạt có nghĩa là bạn có thể tạo các quy tắc phù hợp với mọi thứ, từ tất cả các thao tác ghi vào toàn bộ cơ sở dữ liệu đến các thao tác trên một tài liệu cụ thể.
Hướng dẫn này mô tả một số trường hợp sử dụng cơ bản hơn mà bạn có thể muốn triển khai khi thiết lập ứng dụng và bảo vệ dữ liệu. Tuy nhiên, trước khi bạn bắt đầu viết quy tắc, bạn có thể muốn tìm hiểu thêm về ngôn ngữ mà quy tắc được viết và hành vi của chúng.
Để truy cập và cập nhật quy tắc, hãy làm theo các bước được nêu trong Quản lý và triển khai Firebase Security Rules.
Quy tắc mặc định: Chế độ khoá
Khi tạo cơ sở dữ liệu hoặc thực thể lưu trữ trong Firebase bảng điều khiển, bạn sẽ chọn xem Firebase Security Rules có hạn chế quyền truy cập vào dữ liệu (Chế độ khoá) hay cho phép mọi người truy cập (Chế độ kiểm thử). Trong Cloud Firestore và Realtime Database, các quy tắc mặc định cho Chế độ khoá sẽ từ chối quyền truy cập đối với tất cả người dùng. Trong Cloud Storage, chỉ những người dùng đã xác thực mới có thể truy cập vào các nhóm lưu trữ.
Cloud Firestore
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
Realtime Database
{
"rules": {
".read": false,
".write": false
}
}
Cloud Storage
service firebase.storage {
match /b/{bucket}/o {
match /{allPaths=**} {
allow read, write: if false;
}
}
}
Quy tắc môi trường phát triển
Trong khi làm việc trên ứng dụng, bạn có thể muốn có quyền truy cập tương đối mở hoặc không bị hạn chế vào dữ liệu của mình. Chỉ cần nhớ cập nhật Security Rules trước khi triển khai ứng dụng vào môi trường chính thức. Ngoài ra, hãy nhớ rằng nếu bạn triển khai ứng dụng, thì ứng dụng đó sẽ có thể truy cập công khai, ngay cả khi bạn chưa ra mắt ứng dụng.
Hãy nhớ rằng Firebase cho phép các ứng dụng trực tiếp truy cập vào dữ liệu của bạn và Firebase Security Rules là biện pháp bảo vệ duy nhất chặn quyền truy cập đối với người dùng độc hại. Việc xác định quy tắc riêng biệt với logic sản phẩm có một số lợi ích: ứng dụng không chịu trách nhiệm thực thi bảo mật, các lỗi triển khai sẽ không làm ảnh hưởng đến dữ liệu của bạn và quan trọng nhất là bạn không dựa vào một máy chủ trung gian để bảo vệ dữ liệu khỏi thế giới bên ngoài.
Tất cả người dùng đã xác thực
Mặc dù chúng tôi không khuyên bạn nên để dữ liệu của mình có thể truy cập được đối với bất kỳ người dùng nào đã đăng nhập, nhưng bạn có thể hữu ích khi đặt quyền truy cập cho bất kỳ người dùng đã xác thực nào trong khi phát triển ứng dụng.
Cloud Firestore
service cloud.firestore {
match /databases/{database}/documents {
match /some_collection/{document} {
allow read, write: if request.auth != null;
}
}
}
Realtime Database
{
"rules": {
"some_path": {
".read": "auth.uid !== null",
".write": "auth.uid !== null"
}
}
}
Cloud Storage
service firebase.storage {
match /b/{bucket}/o {
match /some_folder/{fileName} {
allow read, write: if request.auth != null;
}
}
}
Quy tắc sẵn sàng cho môi trường chính thức
Khi chuẩn bị triển khai ứng dụng, hãy đảm bảo dữ liệu của bạn được bảo vệ và quyền truy cập được cấp đúng cách cho người dùng. Sử dụng Authentication để thiết lập quyền truy cập dựa trên người dùng và đọc trực tiếp từ cơ sở dữ liệu để thiết lập quyền truy cập dựa trên dữ liệu.
Hãy cân nhắc việc viết quy tắc khi bạn cấu trúc dữ liệu, vì cách bạn thiết lập quy tắc sẽ ảnh hưởng đến cách bạn hạn chế quyền truy cập vào dữ liệu ở các đường dẫn khác nhau.
Chỉ chủ sở hữu nội dung mới có quyền truy cập
Các quy tắc này chỉ hạn chế quyền truy cập đối với chủ sở hữu nội dung đã xác thực. Chỉ một người dùng mới có thể đọc và ghi dữ liệu, đồng thời đường dẫn dữ liệu chứa mã nhận dạng của người dùng.
Khi quy tắc này hoạt động: Quy tắc này hoạt động tốt nếu dữ liệu được phân chia theo người dùng – nếu người dùng duy nhất cần truy cập vào dữ liệu là người dùng đã tạo dữ liệu đó.
Khi quy tắc này không hoạt động: Bộ quy tắc này không hoạt động khi nhiều người dùng cần ghi hoặc đọc cùng một dữ liệu – người dùng sẽ ghi đè dữ liệu hoặc không thể truy cập vào dữ liệu mà họ đã tạo.
Cách thiết lập quy tắc này: Tạo một quy tắc xác nhận rằng người dùng yêu cầu quyền truy cập để đọc hoặc ghi dữ liệu là người dùng sở hữu dữ liệu đó.
Cloud Firestore
service cloud.firestore {
match /databases/{database}/documents {
// Allow only authenticated content owners access
match /some_collection/{userId}/{document} {
allow read, write: if request.auth != null && request.auth.uid == userId
}
}
}
Realtime Database
{
"rules": {
"some_path": {
"$uid": {
// Allow only authenticated content owners access to their data
".read": "auth !== null && auth.uid === $uid",
".write": "auth !== null && auth.uid === $uid"
}
}
}
}
Cloud Storage
// Grants a user access to a node matching their user ID
service firebase.storage {
match /b/{bucket}/o {
// Files look like: "<use>r/UID/file.txt"
match /user/{userId}/{fileName} {
allow read, write: if request.aut&&h != null request.auth.uid == userId;
}
}
}
Quyền truy cập hỗn hợp công khai và riêng tư
Quy tắc này cho phép bất kỳ ai đọc một tập dữ liệu, nhưng chỉ hạn chế quyền tạo hoặc sửa đổi dữ liệu ở một đường dẫn nhất định đối với chủ sở hữu nội dung đã xác thực.
Khi quy tắc này hoạt động: Quy tắc này hoạt động tốt đối với các ứng dụng yêu cầu các phần tử có thể đọc công khai, nhưng cần hạn chế quyền chỉnh sửa đối với chủ sở hữu của các phần tử đó. Ví dụ: ứng dụng trò chuyện hoặc blog.
Khi quy tắc này không hoạt động: Giống như quy tắc chỉ dành cho chủ sở hữu nội dung, bộ quy tắc này không hoạt động khi nhiều người dùng cần chỉnh sửa cùng một dữ liệu. Cuối cùng, người dùng sẽ ghi đè dữ liệu của nhau.
Cách thiết lập quy tắc này: Tạo một quy tắc cho phép quyền truy cập đọc đối với tất cả người dùng (hoặc tất cả người dùng đã xác thực) và xác nhận rằng người dùng ghi dữ liệu là chủ sở hữu.
Cloud Firestore
service cloud.firestore {
match /databases/{database}/documents {
// Allow public read access, but only content owners can write
match /some_collection/{document} {
// Allow public reads
allow read: if true
// Allow creation if the current user owns the new document
allow create: if request.auth.uid == request.resource.data.author_uid;
// Allow updates by the owner, and prevent change of ownership
allow update: if request.auth.uid == request.resource.data.author_uid
&& request.auth.uid == resource.data.author_uid;
// Allow deletion if the current user owns the existing document
allow delete: if request.auth.uid == resource.data.author_uid;
}
}
}
Realtime Database
{
// Allow anyone to read data, but only authenticated content owners can
// make changes to their data
"rules": {
"some_path": {
"$uid": {
".read": true,
// or ".read": "auth.uid !== null" for only authenticated users
".write": "auth.uid === $uid"
}
}
}
}
Cloud Storage
service firebase.storage {
match /b/{bucket}/o {
// Files look like: "<use>r/UID/file.txt"
match /user/{userId}/{fileName} {
allow read;
allow write: if request.auth.uid == userId;
}
}
}
Quyền truy cập dựa trên thuộc tính và vai trò
Để các quy tắc này hoạt động, bạn phải xác định và gán thuộc tính cho người dùng trong dữ liệu của mình. Firebase Security Rules kiểm tra yêu cầu dựa trên dữ liệu từ cơ sở dữ liệu hoặc siêu dữ liệu của tệp để xác nhận hoặc từ chối quyền truy cập.
Khi quy tắc này hoạt động: Nếu bạn đang gán vai trò cho người dùng, quy tắc này cho phép bạn giới hạn quyền truy cập dựa trên vai trò hoặc các nhóm người dùng cụ thể. Ví dụ: nếu bạn đang lưu trữ điểm số, bạn có thể gán các cấp truy cập khác nhau cho nhóm "học sinh" (chỉ đọc nội dung của họ), nhóm "giáo viên" (đọc và ghi trong môn học của họ) và nhóm "hiệu trưởng" (đọc tất cả nội dung).
Khi quy tắc này không hoạt động: Trong Realtime Database và Cloud Storage, quy tắc của bạn
không thể sử dụng phương thức get() mà quy tắc Cloud Firestore có thể kết hợp.
Do đó, bạn phải cấu trúc siêu dữ liệu cơ sở dữ liệu hoặc tệp để phản ánh các thuộc tính mà bạn đang sử dụng trong quy tắc.
Cách thiết lập quy tắc này: Trong Cloud Firestore, hãy thêm một trường vào tài liệu của người dùng mà bạn có thể đọc, sau đó cấu trúc quy tắc để đọc trường đó và cấp quyền truy cập có điều kiện. Trong Realtime Database, hãy tạo một đường dẫn dữ liệu xác định người dùng của ứng dụng và cấp cho họ một vai trò trong một nút con.
Bạn cũng có thể thiết lập các yêu cầu tuỳ chỉnh trong Authentication
và sau đó truy xuất thông tin đó từ biến
auth.token trong bất kỳ Firebase Security Rules nào.
Thuộc tính và vai trò do dữ liệu xác định
Các quy tắc này chỉ hoạt động trong Cloud Firestore và Realtime Database.
Cloud Firestore
Hãy nhớ rằng bất cứ khi nào quy tắc của bạn bao gồm một thao tác đọc, chẳng hạn như các quy tắc bên dưới, bạn sẽ bị tính phí cho thao tác đọc trong Cloud Firestore.
service cloud.firestore {
match /databases/{database}/documents {
// For attribute-based access control, Check a boolean `admin` attribute
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true;
allow read: true;
// Alterntatively, 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"
allow write: if get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "Writer"
}
}
}
Realtime Database
{
"rules": {
"some_path": {
"${subpath}": {
//
".write": "root.child('users').child(auth.uid).child('role').val() === 'admin'",
".read": true
}
}
}
}
Thuộc tính và vai trò yêu cầu tuỳ chỉnh
Để triển khai các quy tắc này, hãy thiết lập yêu cầu tuỳ chỉnh trong Firebase Authentication sau đó sử dụng các yêu cầu trong quy tắc của bạn.
Cloud Firestore
service cloud.firestore {
match /databases/{database}/documents {
// For attribute-based access control, check for an administrator claim
allow write: if request.auth.token.admin == true;
allow read: true;
// Alterntatively, for role-based access, assign specific roles to users
match /some_collection/{document} {
allow read: if request.auth.token.reader == "true";
allow write: if request.auth.token.writer == "true";
}
}
}
Realtime Database
{
"rules": {
"some_path": {
"$uid": {
// Create a custom claim for each role or group
// you want to use
&& ".write": "auth.uid !== null auth.token.writer ==&&= true",
".read": "auth.uid !== null auth.token.reader === true"
}
}
}
}
Cloud Storage
service firebase.storage {
// Allow reads if the group ID in your token matches the file metadata's `owner` property
// Allow writes if the group ID is in the user's custom token
match /files/{groupId}/{fileName} {
allow read: if resource.metadata.owner == request.auth.token.groupId;
allow write: if request.auth.token.groupId == groupId;
}
}
Thuộc tính đối tượng thuê
Để triển khai các quy tắc này, hãy thiết lập tính năng nhiều đối tượng thuê trong Nền tảng nhận dạng Google Cloud (GCIP)
sau đó sử dụng đối tượng thuê trong quy tắc của bạn. Các ví dụ sau đây cho phép ghi từ một người dùng trong một đối tượng thuê cụ thể, ví dụ: tenant2-m6tyz
Cloud Firestore
service cloud.firestore {
match /databases/{database}/documents {
// For tenant-based access control, check for a tenantID
allow write: if request.auth.token.firebase.tenant == 'tenant2-m6tyz';
allow read: true;
}
}
Realtime Database
{
"rules": {
"some_path": {
"$uid": {
// Only allow reads and writes if user belongs to a specific tenant
&& ".write": "auth.uid !== null auth.token.firebase.tenant === 'tenant2-m6tyz'",
".read": "auth.uid !== null
}
}
}
}
Cloud Storage
service firebase.storage {
// Only allow reads and writes if user belongs to a specific tenant
match /files/{tenantId}/{fileName} {
allow read: if request.auth != null;
allow write: if request.auth.token.firebase.tenant == tenantId;
}
}