Các quy tắc bảo mật của Firebase tận dụng các ngôn ngữ tùy chỉnh, mạnh mẽ, linh hoạt hỗ trợ nhiều mức độ phức tạp và chi tiết. Bạn có thể làm cho Quy tắc cụ thể hoặc chung chung phù hợp với ứng dụng của mình. Các quy tắc Cơ sở dữ liệu thời gian thực sử dụng cú pháp giống như JavaScript trong cấu trúc JSON. Quy tắc Cloud Firestore và Cloud Storage sử dụng ngôn ngữ dựa trên Ngôn ngữ biểu thức chung (CEL) , được xây dựng dựa trên CEL có match
và allow
câu lệnh hỗ trợ quyền truy cập được cấp có điều kiện.
Vì đây là những ngôn ngữ tùy chỉnh, tuy nhiên, có một đường cong học tập. Sử dụng hướng dẫn này để hiểu rõ hơn về ngôn ngữ Quy tắc khi bạn đi sâu hơn vào các quy tắc phức tạp hơn.
Chọn một sản phẩm để tìm hiểu thêm về các quy tắc của nó.
Cấu trúc cơ bản
Cloud Firestore
Quy tắc bảo mật Firebase trong Cloud Firestore và Cloud Storage sử dụng cấu trúc và cú pháp sau:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
Các khái niệm chính sau đây rất quan trọng cần hiểu khi bạn xây dựng các quy tắc:
- Yêu cầu: Phương thức hoặc các phương thức được gọi trong câu lệnh
allow
. Đây là những phương pháp bạn cho phép chạy. Các phương pháp tiêu chuẩn là:get
,list
,create
,update
vàdelete
. Các phương phápread
vàwrite
thuận tiện cho phép truy cập đọc và ghi rộng rãi trên cơ sở dữ liệu hoặc đường dẫn lưu trữ được chỉ định. - Đường dẫn: Cơ sở dữ liệu hoặc vị trí lưu trữ, được biểu diễn dưới dạng đường dẫn URI.
- Quy tắc: Câu lệnh
allow
, bao gồm điều kiện cho phép một yêu cầu nếu nó đánh giá là true.
Mỗi khái niệm này được mô tả chi tiết hơn bên dưới.
Lưu trữ đám mây
Quy tắc bảo mật Firebase trong Cloud Firestore và Cloud Storage sử dụng cấu trúc và cú pháp sau:
service <<name>> {
// Match the resource path.
match <<path>> {
// Allow the request if the following conditions are true.
allow <<methods>> : if <<condition>>
}
}
Các khái niệm chính sau đây rất quan trọng cần hiểu khi bạn xây dựng các quy tắc:
- Yêu cầu: Phương thức hoặc các phương thức được gọi trong câu lệnh
allow
. Đây là những phương pháp bạn cho phép chạy. Các phương pháp tiêu chuẩn là:get
,list
,create
,update
vàdelete
. Các phương phápread
vàwrite
thuận tiện cho phép truy cập đọc và ghi rộng rãi trên cơ sở dữ liệu hoặc đường dẫn lưu trữ được chỉ định. - Đường dẫn: Cơ sở dữ liệu hoặc vị trí lưu trữ, được biểu diễn dưới dạng đường dẫn URI.
- Quy tắc: Câu lệnh
allow
, bao gồm điều kiện cho phép một yêu cầu nếu nó đánh giá là true.
Mỗi khái niệm này được mô tả chi tiết hơn bên dưới.
Cơ sở dữ liệu thời gian thực
Trong Cơ sở dữ liệu thời gian thực, Quy tắc bảo mật Firebase bao gồm các biểu thức giống JavaScript có trong tài liệu JSON.
Họ sử dụng cú pháp sau:
{
"rules": {
"<<path>>": {
// Allow the request if the condition for each method is true.
".read": <<condition>>,
".write": <<condition>>,
".validate": <<condition>>
}
}
}
Có ba yếu tố cơ bản trong quy tắc:
- Đường dẫn: Vị trí cơ sở dữ liệu. Điều này phản ánh cấu trúc JSON của cơ sở dữ liệu của bạn.
- Yêu cầu: Đây là các phương pháp mà quy tắc sử dụng để cấp quyền truy cập. Các quy tắc
read
vàwrite
cấp quyền truy cập đọc và ghi rộng rãi, trong khi các quy tắcvalidate
hoạt động như một xác minh thứ cấp để cấp quyền truy cập dựa trên dữ liệu đến hoặc dữ liệu hiện có. - Điều kiện: Điều kiện cho phép một yêu cầu nếu nó đánh giá là true.
Cấu trúc quy tắc
Cloud Firestore
Các yếu tố cơ bản của quy tắc trong Cloud Firestore và Cloud Storage như sau:
- Khai báo
service
: Khai báo sản phẩm Firebase mà các quy tắc áp dụng. - Khối
match
: Xác định một đường dẫn trong cơ sở dữ liệu hoặc nhóm lưu trữ mà các quy tắc áp dụng. - Câu lệnh
allow
: Cung cấp các điều kiện để cấp quyền truy cập, được phân biệt bởi các phương thức. Các phương thức được hỗ trợ bao gồm:get
,list
,create
,update
,delete
và các phương thức tiện lợiread
vàwrite
. - Khai báo
function
tùy chọn: Cung cấp khả năng kết hợp và kết hợp các điều kiện để sử dụng trên nhiều quy tắc.
service
chứa một hoặc nhiều khối match
với các câu lệnh allow
cung cấp các điều kiện cấp quyền truy cập vào các yêu cầu. Các biến request
và resource
có sẵn để sử dụng trong các điều kiện quy tắc. Ngôn ngữ Quy tắc bảo mật Firebase cũng hỗ trợ khai báo function
.
Phiên bản cú pháp
Câu lệnh syntax
cho biết phiên bản của ngôn ngữ Quy tắc Firebase được sử dụng để viết nguồn. Phiên bản mới nhất của ngôn ngữ là v2
.
rules_version = '2';
service cloud.firestore {
...
}
Nếu không có câu lệnh rules_version
nào được cung cấp, các quy tắc của bạn sẽ được đánh giá bằng cách sử dụng công cụ v1
.
Dịch vụ
Khai báo service
xác định sản phẩm hoặc dịch vụ Firebase áp dụng các quy tắc của bạn. Bạn chỉ có thể bao gồm một khai báo service
cho mỗi tệp nguồn.
Cloud Firestore
service cloud.firestore {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
Lưu trữ đám mây
service firebase.storage {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
Nếu bạn đang xác định các quy tắc cho cả Cloud Firestore và Cloud Storage bằng cách sử dụng Firebase CLI, bạn sẽ phải duy trì chúng trong các tệp riêng biệt.
Cuộc thi đấu
Một khối match
khai báo một mẫu path
được so khớp với đường dẫn cho hoạt động được yêu cầu (đường dẫn đến request.path
). Phần thân của match
phải có một hoặc nhiều khối match
lồng nhau, câu lệnh allow
hoặc khai báo function
. Đường dẫn trong các khối match
lồng nhau có liên quan đến đường dẫn trong khối match
chính.
Mẫu path
là một tên giống như thư mục có thể bao gồm các biến hoặc ký tự đại diện. Mẫu path
cho phép đối sánh phân đoạn một đường dẫn và phân đoạn nhiều đường dẫn. Bất kỳ biến nào bị ràng buộc trong một path
đều hiển thị trong phạm vi match
hoặc bất kỳ phạm vi lồng nhau nào mà path
được khai báo.
Các kết quả phù hợp với một mẫu path
có thể là một phần hoặc toàn bộ:
- Đối sánh từng phần: Mẫu
path
là đối sánh tiền tố của đường dẫnrequest.path
. - Đối sánh hoàn chỉnh: Mẫu
path
khớp với toàn bộ đường dẫnrequest.path
.
Khi một kết hợp hoàn chỉnh được thực hiện, các quy tắc trong khối sẽ được đánh giá. Khi đối sánh từng phần được thực hiện, các quy tắc match
lồng nhau được kiểm tra để xem liệu bất kỳ path
lồng nhau nào sẽ hoàn thành đối sánh hay không.
Các quy tắc trong mỗi match
hoàn chỉnh được đánh giá để xác định xem có cho phép yêu cầu hay không. Nếu bất kỳ quy tắc phù hợp nào cấp quyền truy cập, yêu cầu được cho phép. Nếu không có quy tắc phù hợp nào cấp quyền truy cập, yêu cầu sẽ bị từ chối.
// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
// Partial match.
match /example/{singleSegment} { // `singleSegment` == 'hello'
allow write; // Write rule not evaluated.
// Complete match.
match /nested/path { // `singleSegment` visible in scope.
allow read; // Read rule is evaluated.
}
}
// Complete match.
match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
allow read; // Read rule is evaluated.
}
}
Như ví dụ trên cho thấy, khai báo path
hỗ trợ các biến sau:
- Ký tự đại diện một đoạn: Một biến ký tự đại diện được khai báo trong một đường dẫn bằng cách đặt một biến trong dấu ngoặc nhọn:
{variable}
. Biến này có thể truy cập được trong câu lệnh somatch
dưới dạng mộtstring
. - Ký tự đại diện đệ quy: Ký tự đại diện đệ quy hoặc nhiều phân đoạn khớp với nhiều phân đoạn đường dẫn tại hoặc bên dưới một đường dẫn. Ký tự đại diện này khớp với tất cả các đường dẫn bên dưới vị trí bạn đặt. Bạn có thể khai báo nó bằng cách thêm chuỗi
=**
vào cuối biến phân đoạn của bạn:{variable=**}
. Biến này có thể truy cập được trong câu lệnhmatch
dưới dạng đối tượngpath
.
Cho phép
Khối match
chứa một hoặc nhiều câu lệnh allow
. Đây là những quy tắc thực tế của bạn. Bạn có thể áp dụng quy tắc allow
một hoặc nhiều phương pháp. Các điều kiện trong câu lệnh allow
phải đánh giá thành true để Cloud Firestore hoặc Cloud Storage cấp bất kỳ yêu cầu nào đến. Bạn cũng có thể viết câu lệnh allow
mà không có điều kiện, ví dụ: allow read
. Tuy nhiên, nếu câu lệnh allow
không bao gồm một điều kiện, nó luôn cho phép yêu cầu đối với phương thức đó.
Nếu bất kỳ quy tắc allow
nào đối với phương thức được thỏa mãn, yêu cầu sẽ được cho phép. Ngoài ra, nếu quy tắc rộng hơn cấp quyền truy cập, Quy tắc cấp quyền truy cập và bỏ qua bất kỳ quy tắc chi tiết nào có thể hạn chế quyền truy cập.
Hãy xem xét ví dụ sau, nơi bất kỳ người dùng nào cũng có thể đọc hoặc xóa bất kỳ tệp nào của riêng họ. Quy tắc chi tiết hơn chỉ cho phép ghi nếu người dùng yêu cầu ghi sở hữu tệp và tệp là PNG. Người dùng có thể xóa bất kỳ tệp nào tại đường dẫn con - ngay cả khi chúng không phải là PNG - bởi vì quy tắc trước đó cho phép điều đó.
service firebase.storage {
// Allow the requestor to read or delete any resource on a path under the
// user directory.
match /users/{userId}/{anyUserFile=**} {
allow read, delete: if request.auth != null && request.auth.uid == userId;
}
// Allow the requestor to create or update their own images.
// When 'request.method' == 'delete' this rule and the one matching
// any path under the user directory would both match and the `delete`
// would be permitted.
match /users/{userId}/images/{imageId} {
// Whether to permit the request depends on the logical OR of all
// matched rules. This means that even if this rule did not explicitly
// allow the 'delete' the earlier rule would have.
allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
}
}
Phương pháp
Mỗi câu lệnh allow
bao gồm một phương thức cấp quyền truy cập cho các yêu cầu đến của cùng một phương thức.
Phương pháp | Loại yêu cầu |
---|---|
Phương pháp tiện lợi | |
read | Bất kỳ loại yêu cầu đọc nào |
write | Bất kỳ loại yêu cầu viết nào |
Phương pháp tiêu chuẩn | |
get | Đọc các yêu cầu đối với các tài liệu hoặc tệp đơn lẻ |
list | Đọc yêu cầu cho các truy vấn và bộ sưu tập |
create | Viết tài liệu hoặc tệp mới |
update | Ghi vào tài liệu cơ sở dữ liệu hiện có hoặc cập nhật siêu dữ liệu tệp |
delete | Xóa dữ liệu |
Bạn không thể chồng chéo các phương thức đọc trong cùng một khối match
hoặc các phương thức ghi xung đột trong cùng một khai báo path
.
Ví dụ: các quy tắc sau sẽ không thành công:
service bad.example {
match /rules/with/overlapping/methods {
// This rule allows reads to all authenticated users
allow read: if request.auth != null;
match another/subpath {
// This secondary, more specific read rule causes an error
allow get: if request.auth != null && request.auth.uid == "me";
// Overlapping write methods in the same path cause an error as well
allow write: if request.auth != null;
allow create: if request.auth != null && request.auth.uid == "me";
}
}
}
Chức năng
Khi các quy tắc bảo mật của bạn trở nên phức tạp hơn, bạn có thể muốn đưa các nhóm điều kiện vào các hàm mà bạn có thể sử dụng lại trên bộ quy tắc của mình. Các quy tắc bảo mật hỗ trợ các chức năng tùy chỉnh. Cú pháp cho các hàm tùy chỉnh hơi giống JavaScript, nhưng các hàm quy tắc bảo mật được viết bằng ngôn ngữ dành riêng cho miền có một số hạn chế quan trọng:
- Các hàm chỉ có thể chứa một câu lệnh
return
duy nhất. Chúng không thể chứa bất kỳ logic bổ sung nào. Ví dụ, chúng không thể thực hiện các vòng lặp hoặc gọi các dịch vụ bên ngoài. - Các hàm có thể tự động truy cập các hàm và biến từ phạm vi mà chúng được xác định. Ví dụ: một hàm được xác định trong phạm vi
service cloud.firestore
có quyền truy cập vào biếnresource
và các hàm tích hợp sẵn nhưget()
vàexists()
. - Các hàm có thể gọi các hàm khác nhưng không thể đệ quy. Tổng chiều sâu ngăn xếp cuộc gọi được giới hạn ở 20.
- Trong phiên bản quy tắc
v2
, các hàm có thể xác định các biến bằng cách sử dụng từ khóalet
. Các hàm có thể có tối đa 10 liên kết let, nhưng phải kết thúc bằng câu lệnh trả về.
Một hàm được xác định bằng từ khóa function
và không có hoặc nhiều đối số. Ví dụ: bạn có thể muốn kết hợp hai loại điều kiện được sử dụng trong các ví dụ trên thành một hàm duy nhất:
service cloud.firestore {
match /databases/{database}/documents {
// True if the user is signed in or the requested data is 'public'
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();
}
}
}
Đây là một ví dụ hiển thị các đối số của hàm và phép gán. Các câu lệnh gán phải được phân tách bằng dấu chấm phẩy.
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
return isAuthor || isAdmin;
}
Lưu ý cách phân công isAdmin
thực thi tra cứu bộ sưu tập quản trị viên. Để đánh giá lười biếng mà không yêu cầu tra cứu không cần thiết, hãy tận dụng tính chất đoản mạch của &&
(AND) và ||
(HOẶC) so sánh để gọi một hàm thứ hai chỉ khi isAuthor
được hiển thị là đúng (đối với &&
so sánh) hoặc sai (đối với ||
so sánh).
function isAdmin(userId) {
return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
// `||` is short-circuiting; isAdmin called only if isAuthor == false.
return isAuthor || isAdmin(userId);
}
Việc sử dụng các chức năng trong các quy tắc bảo mật của bạn khiến chúng dễ bảo trì hơn khi mức độ phức tạp của các quy tắc của bạn ngày càng tăng.
Lưu trữ đám mây
Các yếu tố cơ bản của quy tắc trong Cloud Firestore và Cloud Storage như sau:
- Khai báo
service
: Khai báo sản phẩm Firebase mà các quy tắc áp dụng. - Khối
match
: Xác định một đường dẫn trong cơ sở dữ liệu hoặc nhóm lưu trữ mà các quy tắc áp dụng. - Câu lệnh
allow
: Cung cấp các điều kiện để cấp quyền truy cập, được phân biệt bởi các phương thức. Các phương thức được hỗ trợ bao gồm:get
,list
,create
,update
,delete
và các phương thức tiện lợiread
vàwrite
. - Khai báo
function
tùy chọn: Cung cấp khả năng kết hợp và kết hợp các điều kiện để sử dụng trên nhiều quy tắc.
service
chứa một hoặc nhiều khối match
với các câu lệnh allow
cung cấp các điều kiện cấp quyền truy cập vào các yêu cầu. Các biến request
và resource
có sẵn để sử dụng trong các điều kiện quy tắc. Ngôn ngữ Quy tắc bảo mật Firebase cũng hỗ trợ khai báo function
.
Phiên bản cú pháp
Câu lệnh syntax
cho biết phiên bản của ngôn ngữ Quy tắc Firebase được sử dụng để viết nguồn. Phiên bản mới nhất của ngôn ngữ là v2
.
rules_version = '2';
service cloud.firestore {
...
}
Nếu không có câu lệnh rules_version
nào được cung cấp, các quy tắc của bạn sẽ được đánh giá bằng cách sử dụng công cụ v1
.
Dịch vụ
Khai báo service
xác định sản phẩm hoặc dịch vụ Firebase áp dụng các quy tắc của bạn. Bạn chỉ có thể bao gồm một khai báo service
cho mỗi tệp nguồn.
Cloud Firestore
service cloud.firestore {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
Lưu trữ đám mây
service firebase.storage {
// Your 'match' blocks with their corresponding 'allow' statements and
// optional 'function' declarations are contained here
}
Nếu bạn đang xác định các quy tắc cho cả Cloud Firestore và Cloud Storage bằng cách sử dụng Firebase CLI, bạn sẽ phải duy trì chúng trong các tệp riêng biệt.
Cuộc thi đấu
Một khối match
khai báo một mẫu path
được so khớp với đường dẫn cho hoạt động được yêu cầu (đường dẫn đến request.path
). Phần thân của match
phải có một hoặc nhiều khối match
lồng nhau, câu lệnh allow
hoặc khai báo function
. Đường dẫn trong các khối match
lồng nhau có liên quan đến đường dẫn trong khối match
chính.
Mẫu path
là một tên giống như thư mục có thể bao gồm các biến hoặc ký tự đại diện. Mẫu path
cho phép đối sánh phân đoạn một đường dẫn và phân đoạn nhiều đường dẫn. Bất kỳ biến nào bị ràng buộc trong một path
đều hiển thị trong phạm vi match
hoặc bất kỳ phạm vi lồng nhau nào mà path
được khai báo.
Các kết quả phù hợp với một mẫu path
có thể là một phần hoặc toàn bộ:
- Đối sánh từng phần: Mẫu
path
là đối sánh tiền tố của đường dẫnrequest.path
. - Đối sánh hoàn chỉnh: Mẫu
path
khớp với toàn bộ đường dẫnrequest.path
.
Khi một kết hợp hoàn chỉnh được thực hiện, các quy tắc trong khối sẽ được đánh giá. Khi đối sánh từng phần được thực hiện, các quy tắc match
lồng nhau được kiểm tra để xem liệu bất kỳ path
lồng nhau nào sẽ hoàn thành đối sánh hay không.
Các quy tắc trong mỗi match
hoàn chỉnh được đánh giá để xác định xem có cho phép yêu cầu hay không. Nếu bất kỳ quy tắc phù hợp nào cấp quyền truy cập, yêu cầu được cho phép. Nếu không có quy tắc phù hợp nào cấp quyền truy cập, yêu cầu sẽ bị từ chối.
// Given request.path == /example/hello/nested/path the following
// declarations indicate whether they are a partial or complete match and
// the value of any variables visible within the scope.
service firebase.storage {
// Partial match.
match /example/{singleSegment} { // `singleSegment` == 'hello'
allow write; // Write rule not evaluated.
// Complete match.
match /nested/path { // `singleSegment` visible in scope.
allow read; // Read rule is evaluated.
}
}
// Complete match.
match /example/{multiSegment=**} { // `multiSegment` == /hello/nested/path
allow read; // Read rule is evaluated.
}
}
Như ví dụ trên cho thấy, khai báo path
hỗ trợ các biến sau:
- Ký tự đại diện một đoạn: Một biến ký tự đại diện được khai báo trong một đường dẫn bằng cách đặt một biến trong dấu ngoặc nhọn:
{variable}
. Biến này có thể truy cập được trong câu lệnh somatch
dưới dạng mộtstring
. - Ký tự đại diện đệ quy: Ký tự đại diện đệ quy hoặc nhiều phân đoạn khớp với nhiều phân đoạn đường dẫn tại hoặc bên dưới một đường dẫn. Ký tự đại diện này khớp với tất cả các đường dẫn bên dưới vị trí bạn đặt. Bạn có thể khai báo nó bằng cách thêm chuỗi
=**
vào cuối biến phân đoạn của bạn:{variable=**}
. Biến này có thể truy cập được trong câu lệnhmatch
dưới dạng đối tượngpath
.
Cho phép
Khối match
chứa một hoặc nhiều câu lệnh allow
. Đây là những quy tắc thực tế của bạn. Bạn có thể áp dụng quy tắc allow
một hoặc nhiều phương pháp. Các điều kiện trong câu lệnh allow
phải đánh giá thành true để Cloud Firestore hoặc Cloud Storage cấp bất kỳ yêu cầu nào đến. Bạn cũng có thể viết câu lệnh allow
mà không có điều kiện, ví dụ: allow read
. Tuy nhiên, nếu câu lệnh allow
không bao gồm một điều kiện, nó luôn cho phép yêu cầu đối với phương thức đó.
Nếu bất kỳ quy tắc allow
nào đối với phương thức được thỏa mãn, yêu cầu sẽ được cho phép. Ngoài ra, nếu quy tắc rộng hơn cấp quyền truy cập, Quy tắc cấp quyền truy cập và bỏ qua bất kỳ quy tắc chi tiết nào có thể hạn chế quyền truy cập.
Hãy xem xét ví dụ sau, nơi bất kỳ người dùng nào cũng có thể đọc hoặc xóa bất kỳ tệp nào của riêng họ. Quy tắc chi tiết hơn chỉ cho phép ghi nếu người dùng yêu cầu ghi sở hữu tệp và tệp là PNG. Người dùng có thể xóa bất kỳ tệp nào tại đường dẫn con - ngay cả khi chúng không phải là PNG - bởi vì quy tắc trước đó cho phép điều đó.
service firebase.storage {
// Allow the requestor to read or delete any resource on a path under the
// user directory.
match /users/{userId}/{anyUserFile=**} {
allow read, delete: if request.auth != null && request.auth.uid == userId;
}
// Allow the requestor to create or update their own images.
// When 'request.method' == 'delete' this rule and the one matching
// any path under the user directory would both match and the `delete`
// would be permitted.
match /users/{userId}/images/{imageId} {
// Whether to permit the request depends on the logical OR of all
// matched rules. This means that even if this rule did not explicitly
// allow the 'delete' the earlier rule would have.
allow write: if request.auth != null && request.auth.uid == userId && imageId.matches('*.png');
}
}
Phương pháp
Mỗi câu lệnh allow
bao gồm một phương thức cấp quyền truy cập cho các yêu cầu đến của cùng một phương thức.
Phương pháp | Loại yêu cầu |
---|---|
Phương pháp tiện lợi | |
read | Bất kỳ loại yêu cầu đọc nào |
write | Bất kỳ loại yêu cầu viết nào |
Phương pháp tiêu chuẩn | |
get | Đọc các yêu cầu đối với các tài liệu hoặc tệp đơn lẻ |
list | Đọc yêu cầu cho các truy vấn và bộ sưu tập |
create | Viết tài liệu hoặc tệp mới |
update | Ghi vào tài liệu cơ sở dữ liệu hiện có hoặc cập nhật siêu dữ liệu tệp |
delete | Xóa dữ liệu |
Bạn không thể chồng chéo các phương thức đọc trong cùng một khối match
hoặc các phương thức ghi xung đột trong cùng một khai báo path
.
Ví dụ: các quy tắc sau sẽ không thành công:
service bad.example {
match /rules/with/overlapping/methods {
// This rule allows reads to all authenticated users
allow read: if request.auth != null;
match another/subpath {
// This secondary, more specific read rule causes an error
allow get: if request.auth != null && request.auth.uid == "me";
// Overlapping write methods in the same path cause an error as well
allow write: if request.auth != null;
allow create: if request.auth != null && request.auth.uid == "me";
}
}
}
Chức năng
Khi các quy tắc bảo mật của bạn trở nên phức tạp hơn, bạn có thể muốn đưa các nhóm điều kiện vào các hàm mà bạn có thể sử dụng lại trên bộ quy tắc của mình. Các quy tắc bảo mật hỗ trợ các chức năng tùy chỉnh. Cú pháp cho các hàm tùy chỉnh hơi giống JavaScript, nhưng các hàm quy tắc bảo mật được viết bằng ngôn ngữ dành riêng cho miền có một số hạn chế quan trọng:
- Các hàm chỉ có thể chứa một câu lệnh
return
duy nhất. Chúng không thể chứa bất kỳ logic bổ sung nào. Ví dụ, chúng không thể thực hiện các vòng lặp hoặc gọi các dịch vụ bên ngoài. - Các hàm có thể tự động truy cập các hàm và biến từ phạm vi mà chúng được xác định. Ví dụ: một hàm được xác định trong phạm vi
service cloud.firestore
có quyền truy cập vào biếnresource
và các hàm tích hợp sẵn nhưget()
vàexists()
. - Các hàm có thể gọi các hàm khác nhưng không thể đệ quy. Tổng chiều sâu ngăn xếp cuộc gọi được giới hạn ở 20.
- Trong phiên bản quy tắc
v2
, các hàm có thể xác định các biến bằng cách sử dụng từ khóalet
. Các hàm có thể có tối đa 10 liên kết let, nhưng phải kết thúc bằng câu lệnh trả về.
Một hàm được xác định bằng từ khóa function
và không có hoặc nhiều đối số. Ví dụ: bạn có thể muốn kết hợp hai loại điều kiện được sử dụng trong các ví dụ trên thành một hàm duy nhất:
service cloud.firestore {
match /databases/{database}/documents {
// True if the user is signed in or the requested data is 'public'
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();
}
}
}
Đây là một ví dụ hiển thị các đối số của hàm và phép gán. Các câu lệnh gán phải được phân tách bằng dấu chấm phẩy.
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
let isAdmin = exists(/databases/$(database)/documents/admins/$(userId));
return isAuthor || isAdmin;
}
Lưu ý cách phân công isAdmin
thực thi tra cứu bộ sưu tập quản trị viên. Để đánh giá lười biếng mà không yêu cầu tra cứu không cần thiết, hãy tận dụng tính chất đoản mạch của &&
(AND) và ||
(HOẶC) so sánh để gọi một hàm thứ hai chỉ khi isAuthor
được hiển thị là đúng (đối với &&
so sánh) hoặc sai (đối với ||
so sánh).
function isAdmin(userId) {
return exists(/databases/$(database)/documents/admins/$(userId));
}
function isAuthorOrAdmin(userId, article) {
let isAuthor = article.author == userId;
// `||` is short-circuiting; isAdmin called only if isAuthor == false.
return isAuthor || isAdmin(userId);
}
Việc sử dụng các chức năng trong các quy tắc bảo mật của bạn khiến chúng dễ bảo trì hơn khi mức độ phức tạp của các quy tắc của bạn ngày càng tăng.
Cơ sở dữ liệu thời gian thực
Như đã trình bày ở trên, Quy tắc cơ sở dữ liệu thời gian thực bao gồm ba yếu tố cơ bản: vị trí cơ sở dữ liệu như một bản sao của cấu trúc JSON của cơ sở dữ liệu, loại yêu cầu và điều kiện cấp quyền truy cập.
Vị trí cơ sở dữ liệu
Cấu trúc của các quy tắc của bạn phải tuân theo cấu trúc của dữ liệu bạn đã lưu trữ trong cơ sở dữ liệu của mình. Ví dụ: trong ứng dụng trò chuyện có danh sách tin nhắn, bạn có thể có dữ liệu giống như sau:
{
"messages": {
"message0": {
"content": "Hello",
"timestamp": 1405704370369
},
"message1": {
"content": "Goodbye",
"timestamp": 1405704395231
},
...
}
}
Các quy tắc của bạn nên phản ánh cấu trúc đó. Ví dụ:
{
"rules": {
"messages": {
"$message": {
// only messages from the last ten minutes can be read
".read": "data.child('timestamp').val() > (now - 600000)",
// new messages must have a string content and a number timestamp
".validate": "newData.hasChildren(['content', 'timestamp']) &&
newData.child('content').isString() &&
newData.child('timestamp').isNumber()"
}
}
}
}
Như ví dụ trên cho thấy, Quy tắc cơ sở dữ liệu thời gian thực hỗ trợ biến $location
để khớp với các phân đoạn đường dẫn. Sử dụng tiền tố $
phía trước đoạn đường dẫn của bạn để đối sánh quy tắc của bạn với bất kỳ nút con nào dọc theo đường dẫn.
{
"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')"
}
}
}
}
}
Bạn cũng có thể sử dụng $variable
song song với các tên đường dẫn không đổi.
{
"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 }
}
}
}
Phương pháp
Trong Cơ sở dữ liệu thời gian thực, có ba loại quy tắc. Hai trong số các loại quy tắc này - read
và write
- áp dụng cho phương thức của một yêu cầu đến. Loại quy tắc validate
thực thực thi cấu trúc dữ liệu và xác thực định dạng và nội dung của dữ liệu. Quy tắc chạy quy tắc .validate
sau khi xác minh rằng quy tắc .write
cấp quyền truy cập.
Các loại quy tắc | |
---|---|
.đọc | Mô tả nếu và khi nào dữ liệu được phép đọc bởi người dùng. |
.viết | Mô tả nếu và khi nào dữ liệu được phép ghi. |
.validate | Xác định giá trị được định dạng đúng sẽ trông như thế nào, cho dù nó có thuộc tính con và kiểu dữ liệu. |
Theo mặc định, nếu không có quy tắc nào cho phép nó, quyền truy cập tại một đường dẫn sẽ bị từ chối.
Điều kiện xây dựng
Cloud Firestore
Điều kiện là một biểu thức boolean xác định liệu một hoạt động cụ thể nên được phép hay bị từ chối. Các biến request
và resource
cung cấp ngữ cảnh cho các điều kiện đó.
Biến request
Biến request
bao gồm các trường sau và thông tin tương ứng:
request.auth
Mã thông báo web JSON (JWT) chứa thông tin xác thực từ Xác thực Firebase. mã thông báo auth
chứa một tập hợp các xác nhận quyền sở hữu tiêu chuẩn và bất kỳ xác nhận quyền sở hữu tùy chỉnh nào bạn tạo thông qua Xác thực Firebase. Tìm hiểu thêm về Xác thực và Quy tắc bảo mật Firebase .
request.method
request.method
có thể là bất kỳ phương thức tiêu chuẩn nào hoặc phương thức tùy chỉnh. Các phương thức tiện lợi read
và write
cũng tồn tại để đơn giản hóa các quy tắc viết áp dụng cho tất cả các phương pháp tiêu chuẩn chỉ đọc hoặc chỉ ghi tương ứng.
request.params
request.params
bao gồm bất kỳ dữ liệu nào không liên quan cụ thể đến request.resource
có thể hữu ích để đánh giá. Trên thực tế, bản đồ này phải trống đối với tất cả các phương pháp tiêu chuẩn và phải chứa dữ liệu phi tài nguyên cho các phương pháp tùy chỉnh. Các dịch vụ phải cẩn thận để không đổi tên hoặc sửa đổi loại của bất kỳ khóa và giá trị nào được trình bày dưới dạng tham số.
request.path
Đường dẫn request.path
là đường dẫn cho resource
đích. Đường dẫn có liên quan đến dịch vụ. Các đoạn đường dẫn có chứa các ký tự an toàn không phải url chẳng hạn như /
được mã hóa url.
Biến resource
Tài resource
là giá trị hiện tại trong dịch vụ được biểu diễn dưới dạng bản đồ của các cặp khóa-giá trị. Tham chiếu resource
trong một điều kiện sẽ dẫn đến nhiều nhất một lần đọc giá trị từ dịch vụ. Tra cứu này sẽ được tính vào mọi hạn ngạch liên quan đến dịch vụ cho tài nguyên. Đối với yêu cầu get
, resource
sẽ chỉ được tính vào hạn ngạch khi từ chối.
Nhà điều hành và quyền ưu tiên của nhà điều hành
Sử dụng bảng dưới đây làm tài liệu tham khảo cho các toán tử và mức độ ưu tiên tương ứng của chúng trong Quy tắc dành cho Cloud Firestore và Cloud Storage.
Cho các biểu thức a
và b
tùy ý, một trường f
và một chỉ số i
.
Nhà điều hành | Sự miêu tả | Sự liên kết |
---|---|---|
a[i] a() af | Lập chỉ mục, cuộc gọi, truy cập trường | trái sang phải | !a -a | Phủ định đơn nguyên | phải sang trái |
a/ba%ba*b | Toán tử nhân | trái sang phải |
a+b ab | Toán tử cộng | trái sang phải |
a>ba>=ba | Toán tử quan hệ | trái sang phải |
a in b | Sự tồn tại trong danh sách hoặc bản đồ | trái sang phải |
a is type | So sánh kiểu, trong đó type có thể là bool, int, float, number, string, list, map, timestamp, time, path hoặc latlng | trái sang phải |
a==ba!=b | Toán tử so sánh | trái sang phải | a && b | AND có điều kiện | trái sang phải |
a || b | HOẶC có điều kiện | trái sang phải |
a ? true_value : false_value | Biểu thức bậc ba | trái sang phải |
Lưu trữ đám mây
Điều kiện là một biểu thức boolean xác định liệu một hoạt động cụ thể nên được phép hay bị từ chối. Các biến request
và resource
cung cấp ngữ cảnh cho các điều kiện đó.
Biến request
Biến request
bao gồm các trường sau và thông tin tương ứng:
request.auth
Mã thông báo web JSON (JWT) chứa thông tin xác thực từ Xác thực Firebase. mã thông báo auth
chứa một tập hợp các xác nhận quyền sở hữu tiêu chuẩn và bất kỳ xác nhận quyền sở hữu tùy chỉnh nào bạn tạo thông qua Xác thực Firebase. Tìm hiểu thêm về Xác thực và Quy tắc bảo mật Firebase .
request.method
request.method
có thể là bất kỳ phương thức tiêu chuẩn nào hoặc phương thức tùy chỉnh. Các phương thức tiện lợi read
và write
cũng tồn tại để đơn giản hóa các quy tắc viết áp dụng cho tất cả các phương pháp tiêu chuẩn chỉ đọc hoặc chỉ ghi tương ứng.
request.params
request.params
bao gồm bất kỳ dữ liệu nào không liên quan cụ thể đến request.resource
có thể hữu ích để đánh giá. Trên thực tế, bản đồ này phải trống đối với tất cả các phương pháp tiêu chuẩn và phải chứa dữ liệu phi tài nguyên cho các phương pháp tùy chỉnh. Các dịch vụ phải cẩn thận để không đổi tên hoặc sửa đổi loại của bất kỳ khóa và giá trị nào được trình bày dưới dạng tham số.
request.path
Đường dẫn request.path
là đường dẫn cho resource
đích. Đường dẫn có liên quan đến dịch vụ. Các đoạn đường dẫn có chứa các ký tự an toàn không phải url chẳng hạn như /
được mã hóa url.
Biến resource
Tài resource
là giá trị hiện tại trong dịch vụ được biểu diễn dưới dạng bản đồ của các cặp khóa-giá trị. Tham chiếu resource
trong một điều kiện sẽ dẫn đến nhiều nhất một lần đọc giá trị từ dịch vụ. Tra cứu này sẽ được tính vào mọi hạn ngạch liên quan đến dịch vụ cho tài nguyên. Đối với yêu cầu get
, resource
sẽ chỉ được tính vào hạn ngạch khi từ chối.
Các nhà khai thác và quyền ưu tiên của nhà điều hành
Sử dụng bảng dưới đây làm tài liệu tham khảo cho các toán tử và mức độ ưu tiên tương ứng của chúng trong Quy tắc dành cho Cloud Firestore và Cloud Storage.
Cho các biểu thức a
và b
tùy ý, một trường f
và một chỉ số i
.
Nhà điều hành | Sự miêu tả | Sự liên kết |
---|---|---|
a[i] a() af | Lập chỉ mục, cuộc gọi, truy cập trường | trái sang phải | !a -a | Phủ định đơn nguyên | phải sang trái |
a/ba%ba*b | Toán tử nhân | trái sang phải |
a+b ab | Toán tử cộng | trái sang phải |
a>ba>=ba | Toán tử quan hệ | trái sang phải |
a in b | Sự tồn tại trong danh sách hoặc bản đồ | trái sang phải |
a is type | So sánh kiểu, trong đó type có thể là bool, int, float, number, string, list, map, timestamp, time, path hoặc latlng | trái sang phải |
a==ba!=b | Toán tử so sánh | trái sang phải | a && b | AND có điều kiện | trái sang phải |
a || b | HOẶC có điều kiện | trái sang phải |
a ? true_value : false_value | Biểu thức bậc ba | trái sang phải |
Cơ sở dữ liệu thời gian thực
Điều kiện là một biểu thức boolean xác định liệu một hoạt động cụ thể nên được phép hay bị từ chối. Bạn có thể xác định các điều kiện đó trong Quy tắc cơ sở dữ liệu thời gian thực theo những cách sau.
Các biến được xác định trước
Có một số biến hữu ích, được xác định trước có thể được truy cập bên trong định nghĩa quy tắc. Dưới đây là một bản tóm tắt ngắn gọn về từng loại:
Các biến được xác định trước | |
---|---|
Hiện nay | Thời gian hiện tại tính bằng mili giây kể từ kỷ nguyên Linux. Điều này đặc biệt hiệu quả để xác thực dấu thời gian được tạo bằng firebase.database.ServerValue.TIMESTAMP của SDK. |
nguồn gốc | Ảnh chụp RuleDataSnapshot đại diện cho đường dẫn gốc trong cơ sở dữ liệu Firebase khi nó tồn tại trước khi thực hiện thao tác. |
dữ liệu mới | Một RuleDataSnapshot đại diện cho dữ liệu như nó sẽ tồn tại sau khi thử hoạt động. Nó bao gồm dữ liệu mới đang được ghi và dữ liệu hiện có. |
dữ liệu | RuleDataSnapshot đại diện cho dữ liệu như nó đã tồn tại trước khi thực hiện thao tác. |
$ biến | Một đường dẫn ký tự đại diện được sử dụng để đại diện cho id và các khóa con động. |
auth | Đại diện cho trọng tải mã thông báo của người dùng đã xác thực. |
Các biến này có thể được sử dụng ở bất kỳ đâu trong quy tắc của bạn. Ví dụ: các quy tắc bảo mật bên dưới đảm bảo rằng dữ liệu được ghi vào /foo/
node phải là một chuỗi nhỏ hơn 100 ký tự:
{ "rules": { "foo": { // /foo is readable by the world ".read": true, // /foo is writable by the world ".write": true, // data written to /foo must be a string less than 100 characters ".validate": "newData.isString() && newData.val().length < 100" } } }
Quy tắc dựa trên dữ liệu
Bất kỳ dữ liệu nào trong cơ sở dữ liệu của bạn đều có thể được sử dụng trong các quy tắc của bạn. Sử dụng các biến được xác định trước root
, data
và newData
, bạn có thể truy cập vào bất kỳ đường dẫn nào như nó sẽ tồn tại trước hoặc sau một sự kiện ghi.
Hãy xem xét ví dụ này, cho phép các hoạt động ghi miễn là giá trị của nút /allow_writes/
là true
, nút cha không có bộ cờ readOnly
và có một con tên là foo
trong dữ liệu mới được ghi:
".write": "root.child('allow_writes').val() === true && !data.parent().child('readOnly').exists() && newData.child('foo').exists()"
Quy tắc dựa trên truy vấn
Mặc dù bạn không thể sử dụng quy tắc làm bộ lọc, nhưng bạn có thể giới hạn quyền truy cập vào tập hợp con dữ liệu bằng cách sử dụng các tham số truy vấn trong quy tắc của mình. Sử dụng query.
các biểu thức trong quy tắc của bạn để cấp quyền truy cập đọc hoặc ghi dựa trên các tham số truy vấn.
Ví dụ: quy tắc dựa trên truy vấn sau sử dụng quy tắc bảo mật dựa trên người dùng và quy tắc dựa trên truy vấn để hạn chế quyền truy cập vào dữ liệu trong bộ sưu tập baskets
chỉ cho những giỏ hàng mà người dùng đang hoạt động sở hữu:
"baskets": {
".read": "auth.uid != null &&
query.orderByChild == 'owner' &&
query.equalTo == auth.uid" // restrict basket access to owner of basket
}
Truy vấn sau, bao gồm các tham số truy vấn trong quy tắc, sẽ thành công:
db.ref("baskets").orderByChild("owner")
.equalTo(auth.currentUser.uid)
.on("value", cb) // Would succeed
Tuy nhiên, các truy vấn không bao gồm các tham số trong quy tắc sẽ không thành công với lỗi PermissionDenied
:
db.ref("baskets").on("value", cb) // Would fail with PermissionDenied
Bạn cũng có thể sử dụng các quy tắc dựa trên truy vấn để giới hạn lượng dữ liệu khách hàng tải xuống thông qua các thao tác đọc.
Ví dụ: quy tắc sau giới hạn quyền đọc chỉ đối với 1000 kết quả đầu tiên của truy vấn, được sắp xếp theo mức độ ưu tiên:
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.
biểu thức có sẵn trong Quy tắc cơ sở dữ liệu thời gian thực.
Biểu thức quy tắc dựa trên truy vấn | ||
---|---|---|
Biểu hiện | Loại | Sự miêu tả |
query.orderByKey query.orderByPosystem query.orderByValue | boolean | Đúng cho các truy vấn được sắp xếp theo khóa, mức độ ưu tiên hoặc giá trị. Sai khác. |
query.orderByChild | chuỗi vô giá trị | Sử dụng một chuỗi để biểu diễn đường dẫn tương đối đến một nút con. Ví dụ: query.orderByChild == "address/zip" . Nếu truy vấn không được sắp xếp theo thứ tự của nút con, giá trị này là null. |
query.startAt query.endAt query.equalTo | chuỗi số boolean vô giá trị | Truy xuất các giới hạn của truy vấn đang thực thi hoặc trả về null nếu không có tập hợp giới hạn nào. |
query.limitToFirst query.limitToLast | số vô giá trị | Lấy giới hạn trên truy vấn đang thực thi hoặc trả về null nếu không có giới hạn nào được đặt. |
Các nhà khai thác
Quy tắc cơ sở dữ liệu thời gian thực hỗ trợ một số toán tử mà bạn có thể sử dụng để kết hợp các biến trong câu lệnh điều kiện. Xem danh sách đầy đủ các toán tử trong tài liệu tham khảo .
Tạo điều kiện
Các điều kiện thực tế của bạn sẽ thay đổi dựa trên quyền truy cập mà bạn muốn cấp. Các quy tắc cố ý cung cấp một mức độ linh hoạt rất lớn, vì vậy các quy tắc của ứng dụng cuối cùng có thể đơn giản hoặc phức tạp tùy theo nhu cầu của bạn.
Để biết một số hướng dẫn tạo Quy tắc đơn giản, sẵn sàng cho sản xuất, hãy xem Quy tắc bảo mật cơ bản .