Доступ к полю родительских документов в правилах Firestore
Я внедряю книгу рецептов в Firestore, где каждый пользователь может видеть все рецепты, созданные всеми пользователями, но редактировать или удалять рецепт может только оригинальный автор рецепта. Любой пользователь также может создать новый рецепт.
Моя проблема в том, что я не могу настроить разрешения для подколлекции, чтобы "прослушивать" поле родительского документа подколлекций.
Каждый рецепт документа содержит три вещи. Поле называется name
где хранится название рецепта, поле называется creatorUID
где request.auth.uid
из UID создателей хранится и подмножество называется ingredients
содержащие документы с некоторыми случайными полями.
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
match /ListOfRecipes/{recipe} {
allow read, create: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
match /{list=**} {
allow read: if isSignedIn();
// Should return true if recipe.creatorUID has same value as request.auth.uid
allow write: if recipe.creatorUID == request.auth.uid;
}
}
}
}
Проблема в том, что с этими правилами это работает только для создания документа рецепта. Подколлекция и ее документы не создаются, так как БД говорит
FirebaseError: [code= access-denied]: отсутствует или недостаточно разрешений. FirebaseError: Отсутствует или недостаточно разрешений.
Звонки осуществляются с клиента Angular и его официальной библиотеки.
1 ответ
Правила не каскадируются, поэтому вам нужно будет выполнить любые проверки, необходимые для документа, захваченного Правилами.
Вообще говоря, {x=**}
правила чаще являются ошибкой и использование =**
только для особо специфичных случаев использования.
Исходя из вашего вопроса, я предполагаю, что ваш режим данных выглядит примерно так:
/ListofRecipes/{recipe_document}/List/{list_document}
В этом случае вам нужно настроить ваши правила примерно так:
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
match /ListOfRecipes/{recipe} {
allow read, create: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
function recipeData() {
return get(/databases/$(database)/documents/ListOfRecipes/$(recipe)).data
}
match /List/{list} {
allow read: if isSignedIn();
allow write: if recipeData().creatorUID == request.auth.uid;
}
}
}
}
Ответ Дэна выше отлично работает! Просто для справки, в моем случае мне нужен был только идентификатор корневого родительского документа, вы можете использовать переменную из оператора сопоставления над вложенным, например:
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
match /ListOfRecipes/{recipeID} {
allow read, create: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
match /List/{list} {
allow read: if isSignedIn();
allow write: if recipeID == 'XXXXX';
}
}
}
}
Основываясь на ответе Дэна, вы сможете уменьшить количество чтений в своей базе данных для update
а также delete
в подколлекции, добавив creatorUID в документ подколлекции.
Вам придется ограничить create
только создателю и убедитесь, что установлен creatorUID. Вот моя модификация правил Дэна:
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
match /ListOfRecipes/{recipe} {
allow read, create: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
function recipeData() {
return get(/databases/$(database)/documents/ListOfRecipes/$(recipe)).data
}
match /List/{list} {
allow read: if isSignedIn();
allow update, delete: if resource.data.creatorUID == request.auth.uid;
allow create: if recipeData().creatorUID == request.auth.uid
&& request.resource.data.creatorUID == request.auth.uid;
}
}
}
}