Я протестировал эту структуру правил безопасности в консоли Firebase для Firestore, и я думаю, что она делает то, что я хочу, а именно: сохранить карту ролей для пользователей на уровне организация и применить разрешения для организации вложенные коллекции , всегда ссылаясь на родительскую организацию с использованием метода get()
.
service cloud.firestore {
match /databases/{database}/documents {
// ORGANIZATIONS collection
match /organizations/{organization} {
function isSignedIn() {
return request.auth != null;
}
function getRole(rsc) {
// Read from the 'roles' map in the resource (rsc)
return rsc.data.roles[request.auth.uid];
}
function isOneOfRoles(rsc, array) {
// Determine if the user is one of an array of roles
return isSignedIn() && (getRole(rsc) in array);
}
allow write: if isSignedIn();
allow read: if isSignedIn() && isOneOfRoles(resource, ['owner']);
// PROJECTS subcollection
match /projects/{project} {
allow write: if isSignedIn() && isOneOfRoles( get(/databases/$(database)/documents/organizations/$(organization)), ['owner']);
allow read: if isSignedIn() && isOneOfRoles(get(/databases/$(database)/documents/organizations/$(organization)), ['owner', 'member']);
}
}
}
}
Теперь, поскольку запросы должны соответствовать правилам безопасности, я пытаюсь понять, как сделать запрос с использованиемКлиент Javascript, который будет соответствовать приведенным выше правилам безопасности.
У меня есть рабочий запрос для получения организаций, который выглядит следующим образом:
db.collection('organizations').where(`roles.${currentUser.uuid}`, '==', 'owner').get()
, который основан на структуре документа, подобной следующей:
organizations (collection)
{organization} (document)
name: string,
roles: {
<user_id_1>: "owner",
<user_id_2>: "member"
},
projects (subcollection)
Возможно ли иметь запрос (или даже несколько запросов) в клиенте Javascript , который проверяет, что пользователь играет определенную роль на уровне organization
И проверяет свойства документав подколлекции projects
, аналогично правилам безопасности?
РЕДАКТИРОВАТЬ : В конечном счете, яnk это вопрос authorization
и поддерживает ли Firestore мой подход.Похоже, что моя лучшая ставка на данный момент - это рекурсивный синтаксис с подстановочными символами - match /organization/{document=**}
- но поскольку соответствие любому условию позволяет получить доступ ко всем вложенным документам, этот подход выглядит менее безопасным.
В идеале я мог бы указать путь сбора - например, organizations/{organization}/projects
- в своем клиентском запросе и иметь возможность указать, что роли {organization}
должны быть проверены перед предоставлением доступа к projects
поднабор.
ПОТЕНЦИАЛЬНОЕ РЕШЕНИЕ : Следующая структура правил безопасности оставляет желать лучшего, но, похоже, это улучшение.Вместо путей, соответствующих конкретным подколлекциям, я просто использую рекурсивный подстановочный синтаксис.Кто-нибудь знает лучшее решение?
service cloud.firestore {
match /databases/{database}/documents {
function isSignedIn() {
return request.auth != null;
}
function getRole(rsc) {
// Read from the 'roles' map in the resource (rsc)
return rsc.data.roles[request.auth.uid];
}
function isOneOfRoles(rsc, array) {
// Determine if the user is one of an array of roles
return isSignedIn() && (getRole(rsc) in array);
}
// ORGANIZATIONS
match /organizations/{organization} {
allow write: if isOneOfRoles(resource, ['owner']);
allow read: if isOneOfRoles(resource, ['owner', 'member']);
}
// Any subcollections under ORGANIZATION
match /organizations/{organization}/{sub=**} {
allow write: if isOneOfRoles(get(/databases/$(database)/documents/organizations/$(organization)), ['owner']);
allow read: if isOneOfRoles(get(/databases/$(database)/documents/organizations/$(organization)), ['owner', 'member']);
}
}
}