#android #firebase #web #google-cloud-firestore #firebase-security
#Android #firebase #веб #google-облако-firestore #firebase-безопасность
Вопрос:
Мы попытались перечислить все документы из коллекции «события». ( /event/{eventId}
) в документе каждого события существует свойство ‘users’ (массив) со всеми идентификаторами пользователей в событии. У нас есть другая коллекция ‘role’ с ролью каждого пользователя для каждого события. ( /role/{eventId}/userRole/{userId}
)
У нас есть разрешение на получение одного события с
db.collection('event').doc(eventId).get()
Но когда мы попытались (с Android и Web) выполнить запрос, подобный
db.collection('event').where("users", "array-contains", user.uid).get()
мы получили FirebaseError: Missing or insufficient permissions.
Правила события :
match /event/{eventId} {
allow read:
if isAuth() amp;amp;
inEvent(eventId, request.auth.uid);
allow create:
if isAuth() amp;amp;
checkEventName() amp;amp;
isOwner(database) amp;amp;
request.resource.data.users == [];
allow update:
if isAuth() amp;amp;
resource.data.ownerId == request.auth.uid amp;amp;
checkEventName() amp;amp;
isOwner(database) amp;amp;
request.resource.data.mediaCount == resource.data.mediaCount amp;amp;
request.resource.data.users == resource.data.users;
allow delete:
if false;
}
Правила роли :
match /role/{roleId} {
allow read:
if isAuth();
allow write:
if false;
match /userRole/{userRoleId} {
allow read:
if isAuth() amp;amp;
userRoleId == request.auth.uid;
allow create:
if isAuth() amp;amp;
userRoleId == request.auth.uid amp;amp;
exists(/databases/$(database)/documents/event/$(roleId)) amp;amp;
request.resource.data.actual is number amp;amp;
request.resource.data.actual >= 0 amp;amp;
request.resource.data.actual <= 10 amp;amp;
request.resource.data.previous is number amp;amp;
request.resource.data.actual == request.resource.data.previous;
allow update:
if isAuth() amp;amp;
userRoleId == request.auth.uid amp;amp;
request.resource.data.actual == 0 amp;amp;
resource.data.actual != 0;
allow delete:
if false;
}
}
Идентификатор роли соответствует идентификатору события.
В правиле чтения события у нас есть inEvent(EventID, request.auth.uid). Когда мы пишем
function inEvent(eventID, userID) {
return true;
}
запрос работает, но если мы попробуем что-то вроде
return exists(/databases/$(database)/documents/role/$(eventID)/userRole/$(userID));
или
return get(/databases/$(database)/documents/role/$(eventID)/userRole/$(userID)).data.actual >= 10;
мы всегда получаем ошибку разрешения
Мы проверили все данные и правила, но мы не понимаем, почему мы можем получить отдельное событие, но не список. Что мы делаем не так? Можем ли мы использовать get () и exists () для разрешений списка?
Ответ №1:
Правила безопасности Firebase применяются при первом подключении прослушивателя. В этот момент сервер должен иметь возможность подтвердить, что операция чтения навсегда вернет только те документы, на получение которых у вас есть разрешение. В ваших текущих правилах это потребовало бы, чтобы сервер прочитал каждый events
документ, а затем проверил роль пользователя для каждого документа. Это не масштабируемая операция, поэтому сервер не разрешает ее и отклоняет чтение.
Обычно это означает, что информация, которую вы хотите защитить, должна присутствовать в документе, к которому вы пытаетесь разрешить доступ, (или во вложенной коллекции), или в фиксированном расположении для текущего пользователя. Лучшее, что я могу придумать для вашего случая, — это иметь ACL под событием, которое считывается, хотя даже тогда я не совсем уверен, можете ли вы смоделировать его так, чтобы сервер мог статически оценивать.
Также смотрите:
- документация Firebase по защите запросов
- эпизод «Знакомство с Cloud Firestore«, посвященный правилам безопасности
Комментарии:
1. Спасибо за эти пояснения. Мы попытаемся переместить роли в коллекции событий и посмотрим, исправит ли это изменение нашу проблему
2. Мы перемещаем роли в role map в документах событий, таких как здесь : firebase.google.com/docs/firestore/solutions/role-based-access И теперь все работает нормально, проблема решена
3. Я все время забываю, что у нас есть страница документации для этого. Хорошая находка! И приятно слышать, что вы смогли перенести роли в сам документ. Это не только заставляет его работать, но и экономит количество прочитанных документов. 🙂