Hướng dẫn này dựa trên hướng dẫn tìm hiểu cú pháp cốt lõi của ngôn ngữ Firebase Security Rules để cho biết cách thêm điều kiện vào Firebase Security Rules cho Cloud Storage.
Thành phần chính của Cloud Storage Security Rules là điều kiện. Đáp
điều kiện là biểu thức boolean xác định liệu một toán tử cụ thể
được phép hoặc bị từ chối. Đối với các quy tắc cơ bản, sử dụng giá trị cố định true
và false
vì điều kiện hoạt động hoàn toàn tốt. Tuy nhiên, Firebase Security Rules cho ngôn ngữ Cloud Storage cung cấp cho bạn các cách để viết các điều kiện phức tạp hơn có thể:
- Kiểm tra việc xác thực người dùng
- Xác thực dữ liệu đến
Xác thực
Firebase Security Rules cho Cloud Storage tích hợp với Firebase Authentication để cung cấp với phương thức xác thực mạnh mẽ dựa trên người dùng vào Cloud Storage. Điều này cho phép kiểm soát quyền truy cập chi tiết dựa trên các thông báo xác nhận quyền sở hữu mã thông báo Firebase Authentication.
Khi người dùng đã xác thực thực hiện một yêu cầu đối với Cloud Storage,
biến request.auth
được điền bằng uid
của người dùng
(request.auth.uid
) cũng như tuyên bố của Firebase Authentication JWT
(request.auth.token
).
Ngoài ra, khi sử dụng phương thức xác thực tuỳ chỉnh, các thông báo xác nhận quyền sở hữu bổ sung sẽ xuất hiện
trong trường request.auth.token
.
Khi người dùng chưa xác thực thực hiện một yêu cầu, biến request.auth
sẽ là null
.
Khi dùng dữ liệu này, có một số cách phổ biến giúp bạn dùng phương pháp xác thực để bảo mật tệp:
- Công khai: bỏ qua
request.auth
- Riêng tư được xác thực: kiểm tra để đảm bảo rằng
request.auth
không phải lànull
- Chế độ riêng tư của người dùng: kiểm tra để đảm bảo rằng
request.auth.uid
khớp với đường dẫnuid
- Nhóm riêng tư: kiểm tra các thông báo xác nhận quyền sở hữu của mã thông báo tuỳ chỉnh để khớp với thông báo xác nhận quyền sở hữu đã chọn, hoặc đọc siêu dữ liệu tệp để xem trường siêu dữ liệu có tồn tại không
Công khai
Bất kỳ quy tắc nào không xem xét ngữ cảnh request.auth
đều có thể được coi là
public
, vì quy tắc này không xem xét ngữ cảnh xác thực của người dùng.
Những quy tắc này có thể hữu ích khi hiển thị dữ liệu công khai như tài sản trò chơi, âm thanh
tệp hoặc nội dung tĩnh khác.
// Anyone to read a public image if the file is less than 100kB // Anyone can upload a public file ending in '.txt' match /public/{imageId} { allow read: if resource.size < 100 * 1024; allow write: if imageId.matches(".*\\.txt"); }
Riêng tư được xác thực
Trong một số trường hợp nhất định, bạn có thể muốn tất cả người dùng đã xác thực của
vào ứng dụng của bạn chứ không phải bởi người dùng chưa được xác thực. Do request.auth
là null
đối với tất cả người dùng chưa được xác thực, bạn chỉ cần kiểm tra
biến request.auth
tồn tại để yêu cầu xác thực:
// Require authentication on all internal image reads match /internal/{imageId} { allow read: if request.auth != null; }
Chế độ riêng tư của người dùng
Cho đến nay, trường hợp sử dụng phổ biến nhất cho request.auth
là cung cấp
người dùng có quyền chi tiết đối với tệp của họ: từ việc tải ảnh hồ sơ lên
để đọc các tài liệu riêng tư.
Vì các tệp trong Cloud Storage có một "đường dẫn" đầy đủ vào tệp, mọi thứ cần
làm cho một tệp do người dùng kiểm soát là một phần
thông tin trong tiền tố tên tệp (chẳng hạn như uid
của người dùng) mà có thể là
được kiểm tra khi quy tắc được đánh giá:
// Only a user can upload their profile picture, but anyone can view it match /users/{userId}/profilePicture.png { allow read; allow write: if request.auth.uid == userId; }
Nhóm riêng tư
Một trường hợp sử dụng phổ biến khác là cấp quyền của nhóm đối với một đối tượng, chẳng hạn như cho phép nhiều thành viên trong nhóm cộng tác trên một tài liệu dùng chung. Có có một số phương pháp để thực hiện việc này:
- Tạo một mã thông báo tuỳ chỉnh Firebase Authentication chứa thông tin bổ sung về thành viên nhóm (chẳng hạn như mã nhóm)
- Thêm thông tin về nhóm (chẳng hạn như mã nhóm hoặc danh sách
uid
được uỷ quyền) trong siêu dữ liệu tệp
Sau khi được lưu trữ trong siêu dữ liệu tệp hoặc mã thông báo, bạn có thể tham chiếu dữ liệu này từ bên trong quy tắc:
// 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; }
Đánh giá yêu cầu
Các lượt tải lên, tải xuống, thay đổi siêu dữ liệu và xoá được đánh giá bằng cách sử dụng
Đã gửi request
tới Cloud Storage. Ngoài mã nhận dạng duy nhất của người dùng và
tải trọng Firebase Authentication trong đối tượng request.auth
như đã mô tả ở trên,
biến request
chứa đường dẫn tệp nơi yêu cầu đang được
thời gian thực hiện yêu cầu, thời gian nhận yêu cầu và giá trị resource
mới
nếu yêu cầu là lệnh ghi.
Đối tượng request
cũng chứa mã nhận dạng duy nhất của người dùng và
tải trọng Firebase Authentication trong đối tượng request.auth
. Đối tượng này sẽ là
được giải thích kỹ hơn trong phần Bảo mật dựa trên người dùng
của phần Tài liệu.
Dưới đây là danh sách đầy đủ các thuộc tính trong đối tượng request
:
Tài sản | Loại | Mô tả |
---|---|---|
auth |
ánh xạ<chuỗi, chuỗi> | Khi người dùng đăng nhập, hãy cung cấp uid , mã nhận dạng duy nhất của người dùng và token , một bản đồ gồm các thông báo xác nhận JWT Firebase Authentication. Nếu không,
null . |
params |
ánh xạ<chuỗi, chuỗi> | Bản đồ chứa các tham số truy vấn của yêu cầu. |
path |
đường dẫn | path đại diện cho đường dẫn mà yêu cầu đang được
thực hiện tại. |
resource |
map<string, string> | Giá trị tài nguyên mới chỉ hiển thị trên các yêu cầu write .
|
time |
dấu thời gian | Dấu thời gian cho biết thời gian máy chủ đánh giá yêu cầu. |
Đánh giá tài nguyên
Khi đánh giá các quy tắc, bạn cũng nên đánh giá siêu dữ liệu của tệp đang được tải lên, tải xuống, sửa đổi hoặc xoá. Điều này cho phép bạn tạo các quy tắc phức tạp và hiệu quả để thực hiện những việc như chỉ cho phép các tệp có loại nội dung được tải lên hoặc chỉ các tệp lớn hơn kích thước nhất định đã bị xoá.
Firebase Security Rules cho Cloud Storage cung cấp siêu dữ liệu tệp trong resource
chứa các cặp khoá/giá trị của siêu dữ liệu được hiển thị trong một
Đối tượng Cloud Storage. Bạn có thể kiểm tra các thuộc tính này trên các yêu cầu read
hoặc write
để đảm bảo tính toàn vẹn của dữ liệu.
Trên các yêu cầu write
(chẳng hạn như tải lên, cập nhật siêu dữ liệu và xoá), trong
bổ sung vào đối tượng resource
chứa siêu dữ liệu tệp cho tệp đó
hiện tồn tại trên đường dẫn yêu cầu, bạn cũng có thể sử dụng
Đối tượng request.resource
chứa một tập hợp con siêu dữ liệu tệp cần được
nếu được phép ghi. Bạn có thể dùng 2 giá trị này để đảm bảo dữ liệu
tính toàn vẹn hoặc thực thi các quy tắc ràng buộc của ứng dụng như loại tệp hay kích thước tệp.
Dưới đây là danh sách đầy đủ các thuộc tính trong đối tượng resource
:
Tài sản | Loại | Mô tả |
---|---|---|
name |
chuỗi | Tên đầy đủ của đối tượng |
bucket |
chuỗi | Tên của bộ chứa chứa đối tượng này. |
generation |
int | Quá trình tạo đối tượng Google Cloud Storage của đối tượng này. |
metageneration |
int | Google Cloud Storage siêu dữ liệu đối tượng của đối tượng này. |
size |
int | Kích thước của đối tượng tính bằng byte. |
timeCreated |
dấu thời gian | Dấu thời gian thể hiện thời điểm một đối tượng được tạo. |
updated |
dấu thời gian | Dấu thời gian biểu thị thời điểm gần đây nhất một đối tượng được cập nhật. |
md5Hash |
chuỗi | Hàm băm MD5 của đối tượng. |
crc32c |
chuỗi | Hàm băm crc32c của đối tượng. |
etag |
chuỗi | Etag liên kết với đối tượng này. |
contentDisposition |
chuỗi | Bố cục nội dung liên kết với đối tượng này. |
contentEncoding |
chuỗi | Phương thức mã hoá nội dung liên kết với đối tượng này. |
contentLanguage |
chuỗi | Ngôn ngữ của nội dung liên kết với đối tượng này. |
contentType |
chuỗi | Loại nội dung liên kết với đối tượng này. |
metadata |
map<string, string> | Cặp khoá/giá trị của siêu dữ liệu tuỳ chỉnh bổ sung do nhà phát triển chỉ định. |
request.resource
chứa tất cả các mã này, ngoại trừ generation
,
metageneration
, etag
, timeCreated
và updated
.
Cải thiện bằng Cloud Firestore
Bạn có thể truy cập vào các tài liệu trong Cloud Firestore để đánh giá các tiêu chí uỷ quyền khác.
Việc sử dụng các hàm firestore.get()
và firestore.exists()
giúp bảo mật
các quy tắc có thể đánh giá các yêu cầu được gửi đến so với các tài liệu trong Cloud Firestore.
Cả hai hàm firestore.get()
và firestore.exists()
đều dự kiến hoàn toàn
đường dẫn tài liệu cụ thể. Khi sử dụng các biến để tạo đường dẫn cho
firestore.get()
và firestore.exists()
, bạn cần thoát một cách rõ ràng
biến bằng cú pháp $(variable)
.
Trong ví dụ bên dưới, chúng ta thấy một quy tắc chỉ cho phép những người có quyền đọc tệp người dùng là thành viên của các câu lạc bộ cụ thể.
service firebase.storage { match /b/{bucket}/o { match /users/{club}/files/{fileId} { allow read: if club in firestore.get(/databases/(default)/documents/users/$(request.auth.id)).memberships } } }
service firebase.storage { match /b/{bucket}/o { match /users/{userId}/photos/{fileId} { allow read: if firestore.exists(/databases/(default)/documents/users/$(userId)/friends/$(request.auth.id)) } } }
Sau khi bạn tạo và lưu Cloud Storage Security Rules đầu tiên sử dụng những Cloud Firestore này bạn sẽ được nhắc trong bảng điều khiển Firebase hoặc CLI Firebase để cho phép các quyền để kết nối hai sản phẩm này.
Bạn có thể tắt tính năng này bằng cách xoá vai trò IAM, như mô tả trong phần Quản lý và triển khai Firebase Security Rules.
Xác thực dữ liệu
Firebase Security Rules của Cloud Storage cũng có thể được dùng để xác thực dữ liệu, bao gồm
xác thực tên và đường dẫn tệp cũng như các thuộc tính siêu dữ liệu của tệp như
contentType
và size
.
service firebase.storage { match /b/{bucket}/o { match /images/{imageId} { // Only allow uploads of any image file that's less than 5MB allow write: if request.resource.size < 5 * 1024 * 1024 && request.resource.contentType.matches('image/.*'); } } }
Hàm tuỳ chỉnh
Khi Firebase Security Rules trở nên phức tạp hơn, bạn có thể cần gói các tập hợp điều kiện trong các hàm mà bạn có thể sử dụng lại trong bộ quy tắc của mình. Quy tắc bảo mật hỗ trợ các hàm tuỳ chỉnh. Cú pháp cho hàm tuỳ chỉnh hơi giống JavaScript, nhưng các hàm Firebase Security Rules được viết bằng ngôn ngữ đặc thù theo 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. Họ không thể chứa bất kỳ logic bổ sung nào. Ví dụ: các giá trị này không thể thực thi 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 vào các hàm và biến từ phạm vi được xác định. Ví dụ: một hàm được xác định trong
phạm vi
service firebase.storage
có quyền truy cập vào Biếnresource
và chỉ dành cho các hàm tích hợp Cloud Firestore chẳng hạn nhưget()
vàexists()
. - Các hàm có thể gọi các hàm khác nhưng có thể không lặp lại. Tổng chiều sâu ngăn xếp lệnh gọi được giới hạn ở mức 10.
- Trong phiên bản
rules2
, các hàm có thể xác định biến bằng từ khoálet
. Hàm có thể có số lượng liên kết let bất kỳ nhưng phải kết thúc bằng lệnh trả về tuyên bố.
Một hàm được định nghĩa bằng từ khoá function
và nhận giá trị từ 0 trở lên
đố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 firebase.storage {
match /b/{bucket}/o {
// 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 /images/{imageId} {
allow read, write: if signedInOrPublic();
}
match /mp3s/{mp3Ids} {
allow read: if signedInOrPublic();
}
}
}
Việc sử dụng các hàm trong Firebase Security Rules giúp dễ bảo trì hơn do độ phức tạp quy tắc của bạn tăng lên.
Các bước tiếp theo
Sau cuộc thảo luận về các điều kiện này, bạn đã có được kiến thức chuyên sâu hơn hiểu về Quy tắc và sẵn sàng:
Tìm hiểu cách xử lý các trường hợp sử dụng cốt lõi cũng như quy trình phát triển, thử nghiệm và triển khai các quy tắc:
- Viết các quy tắc giải quyết các trường hợp phổ biến.
- Tích luỹ kiến thức bằng cách xem xét những tình huống mà bạn phải phát hiện và tránh những Quy tắc không an toàn.
- Kiểm thử các quy tắc bằng cách sử dụng trình mô phỏng Cloud Storage và thư viện kiểm thử Quy tắc bảo mật chuyên dụng.
- Xem xét các phương thức có sẵn để triển khai Rules.