Catch up on everything announced at Firebase Summit, and learn how Firebase can help you accelerate app development and run your app with confidence. Learn More

Scrittura delle condizioni per le regole di sicurezza di Cloud Firestore

Mantieni tutto organizzato con le raccolte Salva e classifica i contenuti in base alle tue preferenze.

Questa guida si basa sulla guida alle regole di sicurezza strutturate per mostrare come aggiungere condizioni alle regole di sicurezza di Cloud Firestore. Se non hai familiarità con le basi delle regole di sicurezza di Cloud Firestore, consulta la guida introduttiva .

L'elemento costitutivo principale delle regole di sicurezza di Cloud Firestore è la condizione. Una condizione è un'espressione booleana che determina se una particolare operazione deve essere consentita o negata. Usa le regole di sicurezza per scrivere condizioni che controllano l'autenticazione dell'utente, convalidano i dati in entrata o persino accedono ad altre parti del tuo database.

Autenticazione

Uno dei modelli di regole di sicurezza più comuni è il controllo dell'accesso in base allo stato di autenticazione dell'utente. Ad esempio, la tua app potrebbe voler consentire solo agli utenti che hanno eseguito l'accesso di scrivere dati:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to access documents in the "cities" collection
    // only if they are authenticated.
    match /cities/{city} {
      allow read, write: if request.auth != null;
    }
  }
}

Un altro schema comune è assicurarsi che gli utenti possano solo leggere e scrivere i propri dati:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure the uid of the requesting user matches name of the user
    // document. The wildcard expression {userId} makes the userId variable
    // available in rules.
    match /users/{userId} {
      allow read, update, delete: if request.auth != null && request.auth.uid == userId;
      allow create: if request.auth != null;
    }
  }
}

Se la tua app utilizza l'autenticazione Firebase o Google Cloud Identity Platform , la variabile request.auth contiene le informazioni di autenticazione per il client che richiede i dati. Per ulteriori informazioni su request.auth , vedere la documentazione di riferimento .

Convalida dei dati

Molte app archiviano le informazioni di controllo dell'accesso come campi sui documenti nel database. Le regole di sicurezza di Cloud Firestore possono consentire o negare dinamicamente l'accesso in base ai dati del documento:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

La variabile resource si riferisce al documento richiesto e la resource.data è una mappa di tutti i campi e valori memorizzati nel documento. Per ulteriori informazioni sulla variabile resource , vedere la documentazione di riferimento .

Durante la scrittura dei dati, potresti voler confrontare i dati in entrata con quelli esistenti. In questo caso, se il tuo set di regole consente la scrittura in sospeso, la variabile request.resource contiene lo stato futuro del documento. Per le operazioni di update che modificano solo un sottoinsieme dei campi del documento, la variabile request.resource conterrà lo stato del documento in sospeso dopo l'operazione. Puoi controllare i valori dei campi in request.resource per prevenire aggiornamenti dei dati indesiderati o incoerenti:

service cloud.firestore {
  match /databases/{database}/documents {
    // Make sure all cities have a positive population and
    // the name is not changed
    match /cities/{city} {
      allow update: if request.resource.data.population > 0
                    && request.resource.data.name == resource.data.name;
    }
  }
}

Accedi ad altri documenti

Utilizzando le funzioni get() ed exists() , le regole di sicurezza possono valutare le richieste in arrivo rispetto ad altri documenti nel database. Le funzioni get() ed exists() si aspettano entrambe percorsi del documento completamente specificati. Quando si utilizzano le variabili per costruire percorsi per get() ed exists() , è necessario eseguire esplicitamente l'escape delle variabili utilizzando la sintassi $(variable) .

Nell'esempio seguente, la variabile del database viene acquisita dalla dichiarazione di match /databases/{database}/documents e utilizzata per formare il percorso:

service cloud.firestore {
  match /databases/{database}/documents {
    match /cities/{city} {
      // Make sure a 'users' document exists for the requesting user before
      // allowing any writes to the 'cities' collection
      allow create: if request.auth != null && exists(/databases/$(database)/documents/users/$(request.auth.uid))

      // Allow the user to delete cities if their user document has the
      // 'admin' field set to 'true'
      allow delete: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.admin == true
    }
  }
}

Per le scritture, è possibile utilizzare la funzione getAfter() per accedere allo stato di un documento dopo il completamento di una transazione o di un batch di scritture, ma prima che la transazione o il batch venga eseguito. Come get() , la funzione getAfter() accetta un percorso del documento completamente specificato. È possibile utilizzare getAfter() per definire insiemi di scritture che devono essere eseguite insieme come transazione o batch.

Accedi ai limiti di chiamata

Esiste un limite alle chiamate di accesso ai documenti per la valutazione del set di regole:

  • 10 per le richieste di documenti singoli e le richieste di interrogazione.
  • 20 per letture, transazioni e scritture batch di più documenti. Ad ogni operazione vale anche il precedente limite di 10.

    Ad esempio, immagina di creare una richiesta di scrittura in batch con 3 operazioni di scrittura e che le regole di sicurezza utilizzino 2 chiamate di accesso ai documenti per convalidare ogni scrittura. In questo caso, ogni scrittura utilizza 2 delle sue 10 chiamate di accesso e la richiesta di scrittura in batch utilizza 6 delle sue 20 chiamate di accesso.

Il superamento di uno dei limiti provoca un errore di autorizzazione negata. Alcune chiamate di accesso ai documenti potrebbero essere memorizzate nella cache e le chiamate memorizzate nella cache non vengono conteggiate ai fini dei limiti.

Per una spiegazione dettagliata di come questi limiti influiscono sulle transazioni e sulle scritture in batch, vedere la guida per la protezione delle operazioni atomiche .

Accedi a chiamate e prezzi

L'utilizzo di queste funzioni esegue un'operazione di lettura nel database, il che significa che ti verrà addebitato un costo per la lettura dei documenti anche se le tue regole rifiutano la richiesta. Consulta i prezzi di Cloud Firestore per informazioni di fatturazione più specifiche.

Funzioni personalizzate

Man mano che le regole di sicurezza diventano più complesse, potresti voler racchiudere insiemi di condizioni in funzioni che puoi riutilizzare nel tuo set di regole. Le regole di sicurezza supportano funzioni personalizzate. La sintassi per le funzioni personalizzate è un po' come JavaScript, ma le funzioni delle regole di sicurezza sono scritte in un linguaggio specifico del dominio che presenta alcune importanti limitazioni:

  • Le funzioni possono contenere solo una singola istruzione return . Non possono contenere alcuna logica aggiuntiva. Ad esempio, non possono eseguire loop o chiamare servizi esterni.
  • Le funzioni possono accedere automaticamente a funzioni e variabili dall'ambito in cui sono definite. Ad esempio, una funzione definita all'interno dell'ambito del service cloud.firestore ha accesso alla variabile della resource e alle funzioni integrate come get() ed exists() .
  • Le funzioni possono chiamare altre funzioni ma non possono essere ricorrenti. La profondità totale dello stack di chiamate è limitata a 10.
  • Nella versione delle regole v2 , le funzioni possono definire variabili usando la parola chiave let . Le funzioni possono avere fino a 10 let binding, ma devono terminare con un'istruzione return.

Una funzione è definita con la parola chiave function e accetta zero o più argomenti. Ad esempio, potresti voler combinare i due tipi di condizioni utilizzati negli esempi precedenti in un'unica funzione:

service cloud.firestore {
  match /databases/{database}/documents {
    // 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 /cities/{city} {
      allow read, write: if signedInOrPublic();
    }

    match /users/{user} {
      allow read, write: if signedInOrPublic();
    }
  }
}

L'uso delle funzioni nelle regole di sicurezza le rende più gestibili man mano che la complessità delle regole aumenta.

Le regole non sono filtri

Dopo aver protetto i dati e aver iniziato a scrivere query, tieni presente che le regole di sicurezza non sono filtri. Non puoi scrivere una query per tutti i documenti in una raccolta e aspettarti che Cloud Firestore restituisca solo i documenti a cui il client corrente ha l'autorizzazione ad accedere.

Ad esempio, prendi la seguente regola di sicurezza:

service cloud.firestore {
  match /databases/{database}/documents {
    // Allow the user to read data if the document has the 'visibility'
    // field set to 'public'
    match /cities/{city} {
      allow read: if resource.data.visibility == 'public';
    }
  }
}

Negato : questa regola rifiuta la seguente query perché il set di risultati può includere documenti in cui la visibility non è public :

ragnatela
db.collection("cities").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
    });
});

Consentito : questa regola consente la seguente query perché la clausola where("visibility", "==", "public") garantisce che il set di risultati soddisfi la condizione della regola:

ragnatela
db.collection("cities").where("visibility", "==", "public").get()
    .then(function(querySnapshot) {
        querySnapshot.forEach(function(doc) {
            console.log(doc.id, " => ", doc.data());
        });
    });

Le regole di sicurezza di Cloud Firestore valutano ogni query rispetto al suo potenziale risultato e non riesce la richiesta se può restituire un documento che il client non dispone dell'autorizzazione a leggere. Le query devono seguire i vincoli stabiliti dalle regole di sicurezza. Per ulteriori informazioni sulle regole di sicurezza e sulle query, vedere Esecuzione di query sui dati in modo sicuro .

Prossimi passi