Estou tendo problemas em algumas condições nas minhas regras do firestore. No meu caso de uso, tenho 2 tipos de usuários com diferentes declarações personalizadas:
- Um usuário tem customerId e sites (matriz)
- Outro usuário tem customerIds
Meu plano é dar os seguintes acessos:
Permitir consultas para Customers/{customerId} e coleções aninhadas se:
- O usuário tem reivindicações personalizadas customerId == customerId (request.auth.token.customerId == customerId)
- As declarações personalizadas do usuário customerIds contêm customerId (request.auth.token.customerIds.hasAny([customerId])
Permitir consultas para Sites/{siteId} e coleções aninhadas se:
- Os sites de declarações personalizadas do usuário contêm {siteId} e a variável do documento Sites⁄{sites} permissionsToView (matriz) deve conter o customerId das declarações personalizadas do usuário.
- A variável do documento Sites⁄{sites} permissionsToView (array) deve conter as declarações personalizadas do usuário customerId.
Para a primeira permissão estabeleci as seguintes condições:
match /Customers/{customerId}/{document=**} {
allow read, write: if isCustomerAccessible(customerId);
}
function isCustomerAccessible(customerId) {
return
request.auth.token.customerIds.hasAny([customerId]) ||
request.auth.token.customerId == customerId ||
request.auth.token.isSuper;
}
Obter o documento específico permitido do lado do cliente é possível, mas fazer uma consulta que vai recuperar documentos permitidos retorna "permissão negada". O objetivo é permitir a coleta independente da consulta que está sendo executada.
Para a segunda condição fiz o seguinte:
match /Sites/{site}/{document=**} {
allow read: if isSiteAccessibleView(site);
allow write: if isSiteAccessibleEdit(site);
}
function isSiteAccessibleView(site) {
return request.auth != null && (
request.auth.token.isSuper ||
hasSiteViewPermission(site) ||
hasSitePermissionThroughCustomerIds(site)
);
}
function isSiteAccessibleEdit(site) {
return request.auth != null && (
request.auth.token.isSuper ||
hasSiteEditPermission(site) ||
hasSitePermissionThroughCustomerIds(site)
);
}
function hasSiteViewPermission(site) {
let siteDoc = get(/databases/$(database)/documents/Sites/$(site));
let permissionValue = siteDoc.data.permissionsToView;
return permissionValue.hasAny([request.auth.token.customerId]);
}
function hasSiteEditPermission(site) {
let siteDoc = get(/databases/$(database)/documents/Sites/$(site));
let permissionValue = siteDoc.data.permissionsToEdit;
let sites = request.auth.token.sites;
return permissionValue.hasAny([request.auth.token.customerId]) && sites.hasAny([site]);
}
function hasSitePermissionThroughCustomerIds(site) {
let siteDoc = get(/databases/$(database)/documents/Sites/$(site));
let permissionValue = siteDoc.data.permissionsToEdit;
return request.auth.token.customerIds.hasAny(permissionValue);
}
Ambas as condições devem dar acesso a todos os documentos das coleções aninhadas, porém não é permitido obter a coleção Customer/{customerId}/People com um usuário que tenha o customerId correto.
Para reproduzir use as seguintes regras:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
match /Customers/{customerId}/{document=**} {
allow read, write: if isCustomerAccessible(customerId);
}
function isCustomerAccessible(customerId) {
return
request.auth.token.customerIds.hasAny([customerId]) ||
request.auth.token.customerId == customerId ||
request.auth.token.isSuper;
}
}
}
use um lado do cliente e faça login com um usuário. Este usuário deve ter a variável customerId dentro. Ao fazer uma consulta à coleção Customers (que retornará apenas documentos permitidos), ele retornará permissões negadas
const customersCollection = collection(db, "Customers")
const customersQuery = query(
customersCollection,
where("tenantID", "==", tenantID)
)
const docs = await getDocs(customersQuery)