Schreibbedingungen für Cloud Firestore-Sicherheitsregeln

Dieser Leitfaden baut auf dem Leitfaden zur Strukturierung von Sicherheitsregeln auf, um zu zeigen, wie Sie Bedingungen zu Ihren Cloud Firestore-Sicherheitsregeln hinzufügen. Wenn Sie mit den Grundlagen der Cloud Firestore-Sicherheitsregeln nicht vertraut sind, lesen Sie den Leitfaden „ Erste Schritte“.

Der primäre Baustein der Cloud Firestore-Sicherheitsregeln ist die Bedingung. Eine Bedingung ist ein boolescher Ausdruck, der festlegt, ob eine bestimmte Operation zugelassen oder verweigert werden soll. Verwenden Sie Sicherheitsregeln, um Bedingungen zu schreiben, die die Benutzerauthentifizierung überprüfen, eingehende Daten validieren oder sogar auf andere Teile Ihrer Datenbank zugreifen.

Authentifizierung

Eines der häufigsten Sicherheitsregelmuster ist die Steuerung des Zugriffs basierend auf dem Authentifizierungsstatus des Benutzers. Beispielsweise möchte Ihre App möglicherweise nur angemeldeten Benutzern erlauben, Daten zu schreiben:

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;
    }
  }
}

Ein weiteres häufiges Muster besteht darin, sicherzustellen, dass Benutzer nur ihre eigenen Daten lesen und schreiben können:

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;
    }
  }
}

Wenn Ihre App Firebase Authentication oder Google Cloud Identity Platform verwendet, enthält die Variable request.auth die Authentifizierungsinformationen für den Client, der Daten anfordert. Weitere Informationen zu request.auth finden Sie in der Referenzdokumentation .

Datenvalidierung

Viele Apps speichern Zugriffskontrollinformationen als Felder zu Dokumenten in der Datenbank. Cloud Firestore-Sicherheitsregeln können den Zugriff basierend auf Dokumentdaten dynamisch zulassen oder verweigern:

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';
    }
  }
}

Die resource -Variable bezieht sich auf das angeforderte Dokument, und „ resource.data “ ist eine Abbildung aller Felder und Werte, die im Dokument gespeichert sind. Weitere Informationen zur resource finden Sie in der Referenzdokumentation .

Beim Schreiben von Daten möchten Sie möglicherweise eingehende Daten mit vorhandenen Daten vergleichen. Wenn Ihr Regelsatz in diesem Fall den ausstehenden Schreibvorgang zulässt, enthält die Variable request.resource den zukünftigen Status des Dokuments. Bei update , die nur eine Teilmenge der Dokumentfelder ändern, enthält die Variable „ request.resource “ den ausstehenden Dokumentstatus nach dem Vorgang. Sie können die Feldwerte in request.resource , um unerwünschte oder inkonsistente Datenaktualisierungen zu verhindern:

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;
    }
  }
}

Greifen Sie auf andere Dokumente zu

Mit den Funktionen get() exists() können Ihre Sicherheitsregeln eingehende Anfragen mit anderen Dokumenten in der Datenbank vergleichen. Die Funktionen get() exists() erwarten beide vollständig angegebene Dokumentpfade. Wenn Sie Variablen verwenden, um Pfade für get() und exists() zu erstellen, müssen Sie Variablen explizit mit der $(variable) -Syntax maskieren.

Im folgenden Beispiel wird die database von der match-Anweisung match /databases/{database}/documents und verwendet, um den Pfad zu bilden:

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
    }
  }
}

Für Schreibvorgänge können Sie die getAfter() Funktion verwenden, um auf den Status eines Dokuments zuzugreifen, nachdem eine Transaktion oder ein Batch von Schreibvorgängen abgeschlossen ist, aber bevor die Transaktion oder der Batch festgeschrieben wird. Wie get() nimmt die Funktion getAfter() einen vollständig angegebenen Dokumentpfad. Sie können getAfter() verwenden, um Sätze von Schreibvorgängen zu definieren, die zusammen als Transaktion oder Batch stattfinden müssen.

Greifen Sie auf Anruflimits zu

Es gibt ein Limit für Dokumentzugriffsaufrufe pro Regelsatzauswertung:

  • 10 für Einzeldokumentanforderungen und Abfrageanforderungen.
  • 20 für das Lesen mehrerer Dokumente, Transaktionen und gestapelte Schreibvorgänge. Das vorherige Limit von 10 gilt auch für jede Operation.

    Stellen Sie sich beispielsweise vor, Sie erstellen eine Batch-Schreibanforderung mit 3 Schreibvorgängen und Ihre Sicherheitsregeln verwenden 2 Dokumentzugriffsaufrufe, um jeden Schreibvorgang zu validieren. In diesem Fall verwendet jeder Schreibvorgang 2 seiner 10 Zugriffsaufrufe und die Batch-Schreibanforderung verwendet 6 seiner 20 Zugriffsaufrufe.

Das Überschreiten eines der beiden Grenzwerte führt zu einem Fehler „Berechtigung verweigert“. Einige Dokumentzugriffsaufrufe können zwischengespeichert werden, und zwischengespeicherte Aufrufe werden nicht auf die Grenzwerte angerechnet.

Eine ausführliche Erläuterung dazu, wie sich diese Beschränkungen auf Transaktionen und Batch-Schreibvorgänge auswirken, finden Sie im Leitfaden zum Sichern atomarer Vorgänge .

Zugriff auf Anrufe und Preise

Die Verwendung dieser Funktionen führt einen Lesevorgang in Ihrer Datenbank aus, was bedeutet, dass Ihnen das Lesen von Dokumenten in Rechnung gestellt wird, selbst wenn Ihre Regeln die Anforderung ablehnen. Genauere Abrechnungsinformationen finden Sie unter Cloud Firestore-Preise .

Benutzerdefinierte Funktionen

Wenn Ihre Sicherheitsregeln komplexer werden, möchten Sie möglicherweise Sätze von Bedingungen in Funktionen einschließen, die Sie in Ihrem Regelsatz wiederverwenden können. Sicherheitsregeln unterstützen benutzerdefinierte Funktionen. Die Syntax für benutzerdefinierte Funktionen ist ein bisschen wie JavaScript, aber Sicherheitsregelfunktionen sind in einer domänenspezifischen Sprache geschrieben, die einige wichtige Einschränkungen hat:

  • Funktionen können nur eine einzige return -Anweisung enthalten. Sie dürfen keine zusätzliche Logik enthalten. Sie können beispielsweise keine Schleifen ausführen oder externe Dienste aufrufen.
  • Funktionen können automatisch auf Funktionen und Variablen aus dem Gültigkeitsbereich zugreifen, in dem sie definiert sind. Beispielsweise hat eine im Bereich service cloud.firestore definierte Funktion Zugriff auf die resource und integrierte Funktionen wie get() undexists exists() .
  • Funktionen können andere Funktionen aufrufen, dürfen aber nicht rekursiv sein. Die gesamte Call-Stack-Tiefe ist auf 10 begrenzt.
  • In der Rules-Version v2 können Funktionen Variablen mit dem Schlüsselwort let definieren. Funktionen können bis zu 10 let-Bindungen haben, müssen aber mit einer return-Anweisung enden.

Eine Funktion wird mit dem Schlüsselwort function definiert und akzeptiert null oder mehr Argumente. Beispielsweise möchten Sie möglicherweise die beiden Arten von Bedingungen, die in den obigen Beispielen verwendet werden, in einer einzigen Funktion kombinieren:

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();
    }
  }
}

Die Verwendung von Funktionen in Ihren Sicherheitsregeln macht sie wartungsfreundlicher, wenn die Komplexität Ihrer Regeln zunimmt.

Regeln sind keine Filter

Denken Sie nach dem Sichern Ihrer Daten und dem Schreiben von Abfragen daran, dass Sicherheitsregeln keine Filter sind. Sie können keine Abfrage für alle Dokumente in einer Sammlung schreiben und erwarten, dass Cloud Firestore nur die Dokumente zurückgibt, auf die der aktuelle Client zugreifen darf.

Nehmen Sie zum Beispiel die folgende Sicherheitsregel:

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';
    }
  }
}

Verweigert : Diese Regel lehnt die folgende Abfrage ab, da die Ergebnismenge Dokumente enthalten kann, deren visibility nicht public ist:

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

Allowed : Diese Regel lässt die folgende Abfrage zu, da die where("visibility", "==", "public") Klausel garantiert, dass die Ergebnismenge die Bedingung der Regel erfüllt:

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

Cloud Firestore-Sicherheitsregeln werten jede Abfrage anhand ihres potenziellen Ergebnisses aus und lassen die Anforderung fehlschlagen, wenn sie ein Dokument zurückgeben könnte, für das der Client keine Leseberechtigung hat. Abfragen müssen den von Ihren Sicherheitsregeln festgelegten Einschränkungen entsprechen. Weitere Informationen zu Sicherheitsregeln und Abfragen finden Sie unter Daten sicher abfragen .

Nächste Schritte