Secure Data Connect mit Autorisierung und Attestierung

Firebase Data Connect bietet eine robuste clientseitige Sicherheit mit:

  • Autorisierung von Mobil- und Webclients
  • Autorisierungssteuerung auf Ebene einzelner Abfragen und Mutationen
  • App-Attestierung mit Firebase App Check

Data Connect erweitert diese Sicherheit durch:

  • Serverseitige Autorisierung
  • Firebase-Projekt- und Cloud SQL-Nutzersicherheit mit IAM

Clientabfragen und ‑mutationen autorisieren

Data Connect ist vollständig in Firebase Authentication integriert. Sie können also umfangreiche Daten zu Nutzern, die auf Ihre Daten zugreifen (Authentifizierung), in Ihrem Design verwenden, um festzulegen, auf welche Daten diese Nutzer zugreifen können (Autorisierung).

Data Connect bietet eine @auth-Richtlinie für Abfragen und Mutationen, mit der Sie die Authentifizierungsebene festlegen können, die für die Autorisierung des Vorgangs erforderlich ist. In diesem Leitfaden wird die @auth-Anweisung mit Beispielen vorgestellt.

Außerdem unterstützt Data Connect die Ausführung von Abfragen, die in Mutationen eingebettet sind. So können Sie zusätzliche Autorisierungskriterien abrufen, die Sie in Ihrer Datenbank gespeichert haben, und diese Kriterien in @check-Richtlinien verwenden, um zu entscheiden, ob umschließende Mutationen autorisiert sind. Bei dieser Autorisierungsart können Sie mit der @redact-Richtlinie festlegen, ob Abfrageergebnisse an Clients im Wire-Protokoll zurückgegeben und die eingebettete Abfrage in generierten SDKs ausgelassen werden. Einführung in diese Richtlinien mit Beispielen

@auth-Richtlinie

Sie können die @auth-Richtlinie so parametrisieren, dass sie einer der vordefinierten Zugriffsebenen folgt, die viele gängige Zugriffsszenarien abdecken. Diese Ebenen reichen von PUBLIC (Zugriff auf Abfragen und Mutationen von allen Clients ohne Authentifizierung) bis NO_ACCESS (Zugriff auf Abfragen und Mutationen nur in privilegierten Serverumgebungen mit dem Firebase Admin SDK). Jede dieser Ebenen ist mit Authentifizierungsabläufen von Firebase Authentication verknüpft.

Level Definition
PUBLIC Der Vorgang kann von jeder Person mit oder ohne Authentifizierung ausgeführt werden.
PUBLIC Der Vorgang kann von jeder Person mit oder ohne Authentifizierung ausgeführt werden.
USER_ANON Jeder identifizierte Nutzer, einschließlich derer, die sich mit Firebase Authentication anonym angemeldet haben, ist berechtigt, die Abfrage oder Mutation auszuführen.
USER Jeder Nutzer, der sich mit Firebase Authentication angemeldet hat, ist berechtigt, die Abfrage oder Mutation auszuführen, mit Ausnahme von Nutzern mit anonymer Anmeldung.
USER_EMAIL_VERIFIED Jeder Nutzer, der sich mit Firebase Authentication und einer bestätigten E-Mail-Adresse angemeldet hat, ist berechtigt, die Abfrage oder Mutation auszuführen.
NO_ACCESS Dieser Vorgang kann nicht außerhalb eines Admin SDK-Kontexts ausgeführt werden.

Anhand dieser vordefinierten Zugriffsebenen können Sie komplexe und robuste Autorisierungsüberprüfungen in der @auth-Richtlinie mit where-Filtern und CEL-Ausdrücken (Common Expression Language) definieren, die auf dem Server ausgewertet werden.

@auth-Anweisung zum Implementieren gängiger Autorisierungsszenarien verwenden

Die voreingestellten Zugriffsebenen sind der Ausgangspunkt für die Autorisierung.

Die Zugriffsebene USER ist die am häufigsten verwendete grundlegende Ebene.

Der vollständig sichere Zugriff basiert auf der USER-Ebene sowie auf Filtern und Ausdrücken, die Nutzerattribute, Ressourcenattribute, Rollen und andere Prüfungen prüfen. Die Ebenen USER_ANON und USER_EMAIL_VERIFIED sind Varianten des USER-Falls.

Mit der Ausdruckssyntax können Sie Daten mit einem auth-Objekt auswerten, das Authentifizierungsdaten darstellt, die mit Vorgängen übergeben werden. Dazu gehören sowohl Standarddaten in Authentifizierungstokens als auch benutzerdefinierte Daten in Tokens. Eine Liste der im auth-Objekt verfügbaren Felder finden Sie im Referenzabschnitt.

Es gibt natürlich Anwendungsfälle, in denen PUBLIC die richtige Zugriffsebene ist. Auch hier ist eine Zugriffsebene immer ein Ausgangspunkt. Für eine robuste Sicherheit sind zusätzliche Filter und Ausdrücke erforderlich.

In diesem Leitfaden finden Sie nun Beispiele dafür, wie Sie auf USER und PUBLIC aufbauen können.

Ein motivierendes Beispiel

Die folgenden Best Practices beziehen sich auf das folgende Schema für eine Blogging-Plattform, bei der bestimmte Inhalte nur mit einem kostenpflichtigen Abo zugänglich sind.

Eine solche Plattform würde wahrscheinlich Users und Posts modellieren.

type User @table(key: "uid") {
  uid: String!
  name: String
  birthday: Date
  createdAt: Timestamp! @default(expr: "request.time")
}

type Post @table {
  author: User!
  text: String!
  # "one of 'draft', 'public', or 'pro'"
  visibility: String! @default(value: "draft")
  # "the time at which the post should be considered published. defaults to
  # immediately"
  publishedAt: Timestamp! @default(expr: "request.time")
  createdAt: Timestamp! @default(expr: "request.time")
  updatedAt: Timestamp! @default(expr: "request.time")
}

Dem Nutzer gehörende Ressourcen

Firebase empfiehlt, Filter und Ausdrücke zu erstellen, mit denen die Inhaberschaft von Nutzern an einer Ressource geprüft wird. In den folgenden Fällen ist das die Inhaberschaft von Posts.

In den folgenden Beispielen werden Daten aus Authentifizierungstokens mithilfe von Ausdrücken gelesen und verglichen. Normalerweise werden Ausdrücke wie where: {authorUid: {eq_expr: "auth.uid"}} verwendet, um eine gespeicherte authorUid mit der auth.uid (User-ID) zu vergleichen, die im Authentifizierungstoken übergeben wird.

Erstellen

Bei dieser Autorisierungsmethode wird der auth.uid aus dem Authentifizierungstoken jedem neuen Post als authorUid-Feld hinzugefügt, um einen Vergleich in nachfolgenden Autorisierungstests zu ermöglichen.

# Create a new post as the current user
mutation CreatePost($text: String!, $visibility: String) @auth(level: USER) {
  post_insert(data: {
    # set the author's uid to the current user uid
    authorUid_expr: "auth.uid"
    text: $text
    visibility: $visibility
  })
}
Aktualisieren

Wenn ein Client versucht, eine Post zu aktualisieren, kannst du die übergebene auth.uid mit der gespeicherten authorUid vergleichen.

# Update one of the current user's posts
mutation UpdatePost($id: UUID!, $text: String, $visibility: String) @auth(level:USER) {
  post_update(
    # only update posts whose author is the current user
    first: { where: {
      id: {eq: $id}
      authorUid: {eq_expr: "auth.uid"}
    }}
    data: {
      text: $text
      visibility: $visibility
      # insert the current server time for updatedAt
      updatedAt_expr: "request.time"
    }
  )
}
Löschen

Dasselbe Verfahren wird verwendet, um Löschvorgänge zu autorisieren.

# Delete one of the current user's posts
mutation DeletePost($id: UUID!) @auth(level: USER) {
  post_delete(
    # only delete posts whose author is the current user
    first: { where: {
      id: {eq: $id}
      authorUid: {eq_expr: "auth.uid"}
    }}
  )
}
# Common display information for a post
fragment DisplayPost on Post {
  id, text, createdAt, updatedAt
  author { uid, name }
}
Liste
# List all posts belonging to the current user
query ListMyPosts @auth(level: USER) {
  posts(where: {
    userUid: {eq_expr: "auth.uid"}
  }) {
    # See the fragment above
    ...DisplayPost
    # also show visibility since it is user-controlled
    visibility
  }
}
Get
# Get a post only if it belongs to the current user
query GetMyPost($id: UUID!) @auth(level: USER) {
  post(key: {id: $id},
    first: {where: {
      id: {eq: $id}
      authorUid: {eq_expr: "auth.uid"}}
      }}, {
      # See the fragment above
      ...DisplayPost
      # also show visibility since it is user-controlled
      visibility
  }
}

Daten filtern

Mit dem Autorisierungssystem von Data Connect können Sie komplexe Filter in Kombination mit vordefinierten Zugriffsebenen wie PUBLIC erstellen und Daten aus Authentifizierungstokens verwenden.

Mit dem Autorisierungssystem können Sie auch nur Ausdrücke ohne Basiszugriffsebene verwenden, wie in einigen der folgenden Beispiele gezeigt.

Nach Ressourcenattributen filtern

Hier basiert die Autorisierung nicht auf Authentifizierungstokens, da die Basissicherheitsebene auf PUBLIC festgelegt ist. Wir können jedoch Datensätze in unserer Datenbank explizit für den öffentlichen Zugriff freigeben. Angenommen, wir haben Post Datensätze in unserer Datenbank, für die visibility auf „öffentlich“ festgelegt ist.

# List all posts marked as 'public' visibility
query ListPublicPosts @auth(level: PUBLIC) {
  posts(where: {
    # Test that visibility is "public"
    visibility: {eq: "public"}
    # Only display articles that are already published
    publishedAt: {lt_expr: "request.time"}
  }) {
    # see the fragment above
    ...DisplayPost
  }
}
Nach Nutzeransprüchen filtern

Angenommen, Sie haben benutzerdefinierte Nutzeransprüche eingerichtet, die Authentifizierungstokens übergeben, um Nutzer mit einem Pro-Abo für Ihre App zu identifizieren, die im Authentifizierungstoken mit einem auth.token.plan-Feld gekennzeichnet sind. Ihre Ausdrücke können anhand dieses Felds getestet werden.

# List all public or pro posts, only permitted if user has "pro" plan claim
query ProListPosts @auth(expr: "auth.token.plan == 'pro'") {
  posts(where: {
    # display both public posts and "pro" posts
    visibility: {in: ['public', 'pro']},
    # only display articles that are already published
    publishedAt: {lt_expr: "request.time"},
  }) {
    # see the fragment above
    ...DisplayPost
    # show visibility so pro users can see which posts are pro\
    visibility
  }
}
Nach Reihenfolge und Limit filtern

Möglicherweise haben Sie auch visibility in Post-Einträgen festgelegt, um anzugeben, dass es sich um Inhalte handelt, die nur für „Pro“-Nutzer verfügbar sind. Für eine Vorschau oder einen Teaser-Eintrag von Daten können Sie die Anzahl der zurückgegebenen Einträge weiter einschränken.

# Show 2 oldest Pro post as a preview
query ProTeaser @auth(level: USER) {
  posts(
    where: {
      # show only pro posts
      visibility: {eq: "pro"}
      # that have already been published more than 30 days ago
      publishedAt: {lt_time: {now: true, sub: {days: 30}}}
    },
    # order by publish time
    orderBy: [{publishedAt: DESC}],
    # only return two posts
    limit: 2
  ) {
    # See the fragment above
    ...DisplayPost
  }
}
Nach Rolle filtern

Wenn Ihre benutzerdefinierte Anspruchsklasse eine admin-Rolle definiert, können Sie Vorgänge entsprechend testen und autorisieren.

# List all posts unconditionally iff the current user has an admin claim
query AdminListPosts @auth(expr: "auth.token.admin == true") {
  posts { ...DisplayPost }
}

@check- und @redact-Richtlinien

Mit der Anweisung @check wird geprüft, ob die angegebenen Felder in den Abfrageergebnissen vorhanden sind. Feldwerte werden mit einem Common Expression Language-Ausdruck (CEL) getestet. Standardmäßig werden mit der Anweisung Knoten mit dem Wert null geprüft und abgelehnt.

Mit der @redact-Richtlinie wird ein Teil der Antwort des Clients entfernt. Ausgeblendete Felder werden weiterhin auf Nebenwirkungen (einschließlich Datenänderungen und @check) geprüft und die Ergebnisse sind für nachfolgende Schritte in CEL-Ausdrücken weiterhin verfügbar.

In Data Connect werden die Direktiven @check und @redact am häufigsten im Zusammenhang mit Autorisierungsüberprüfungen verwendet. Weitere Informationen finden Sie unter Suche nach Autorisierungsdaten.

@check- und @redact-Richtlinien hinzufügen, um Autorisierungsdaten abzurufen

Ein gängiger Anwendungsfall für die Autorisierung besteht darin, benutzerdefinierte Autorisierungsrollen in Ihrer Datenbank zu speichern, z. B. in einer speziellen Berechtigungstabelle, und diese Rollen zu verwenden, um Mutationen zum Erstellen, Aktualisieren oder Löschen von Daten zu autorisieren.

Mithilfe von Autorisierungsdatenabfragen können Sie anhand einer Nutzer-ID nach Rollen suchen und mit CEL-Ausdrücken entscheiden, ob die Mutation autorisiert ist. Beispiel: Sie möchten eine UpdateMovieTitle-Mutation schreiben, mit der ein autorisierter Kunde Filmtitel aktualisieren kann.

Angenommen, in der Datenbank der Filmkritik-App wird eine Autorisierungsrolle in einer Tabelle MoviePermission gespeichert.

# MoviePermission
# Suppose a user has an authorization role with respect to records in the Movie table
type MoviePermission @table(key: ["doc", "userId"]) {
  movie: Movie! # implies another field: movieId: UUID!
  userId: String! # Can also be a reference to a User table, doesn't matter
  role: String!
}

In der folgenden Beispielimplementierung enthält die UpdateMovieTitle-Mutation ein query-Feld, um Daten aus MoviePermission abzurufen, sowie die folgenden Anweisungen, um für eine sichere und robuste Ausführung zu sorgen:

  • Eine @transaction-Richtlinie, die dafür sorgt, dass alle Autorisierungsanfragen und ‑prüfungen atomar abgeschlossen oder fehlschlagen.
  • Die @redact-Richtlinie zum Auslassen von Abfrageergebnissen aus der Antwort. Das bedeutet, dass unsere Autorisierungsüberprüfung auf dem Data Connect-Server ausgeführt wird, aber vertrauliche Daten nicht für den Client freigegeben werden.
  • Zwei @check-Direktiven zur Auswertung der Autorisierungslogik für Abfrageergebnisse, z. B. zum Testen, ob eine bestimmte Nutzer-ID eine geeignete Rolle für Änderungen hat.

mutation UpdateMovieTitle($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
  # Step 1: Query and check
  query @redact {
    moviePermission( # Look up a join table called MoviePermission with a compound key.
      key: {movieId: $movieId, userId_expr: "auth.uid"}
    # Step 1a: Use @check to test if the user has any role associated with the movie
    # Here the `this` binding refers the lookup result, i.e. a MoviePermission object or null
    # The `this != null` expression could be omitted since rejecting on null is default behavior
    ) @check(expr: "this != null", message: "You do not have access to this movie") {
      # Step 1b: Check if the user has the editor role for the movie
      # Next we execute another @check; now `this` refers to the contents of the `role` field
      role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
    }
  }
  # Step 2: Act
  movie_update(id: $movieId, data: {
    title: $newTitle
  })
}

Antimuster bei der Autorisierung, die Sie vermeiden sollten

Im vorherigen Abschnitt wurden Muster beschrieben, die bei der Verwendung der @auth-Richtlinie beachtet werden sollten.

Außerdem sollten Sie wichtige Antimuster kennen, die Sie vermeiden sollten.

IDs von Nutzerattributen und Authentifizierungstoken-Parameter nicht in Abfrage- und Mutationsargumente übergeben

Firebase Authentication ist ein leistungsstarkes Tool zum Präsentieren von Authentifizierungsabläufen und zum sicheren Erfassen von Authentifizierungsdaten wie registrierten Nutzer-IDs und zahlreichen Feldern, die in Authentifizierungstokens gespeichert sind.

Es wird nicht empfohlen, Nutzer-IDs und Authentifizierungstoken in Abfrage- und Mutationsargumenten zu übergeben.

# Antipattern!
# This incorrectly allows any user to view any other user's posts
query AllMyPosts($userId: String!) @auth(level: USER) {
  posts(where: {authorUid: {eq: $userId}}) {
    id, text, createdAt
  }
}

Verwenden Sie die Zugriffsebene USER nicht ohne Filter.

Wie bereits mehrfach in diesem Leitfaden erwähnt, sind die Hauptzugriffsebenen wie USER, USER_ANON und USER_EMAIL_VERIFIED Ausgangspunkte für Autorisierungsüberprüfungen, die mit Filtern und Ausdrücken erweitert werden können. Die Verwendung dieser Ebenen ohne entsprechenden Filter oder Ausdruck, der prüft, welcher Nutzer die Anfrage ausführt, entspricht im Wesentlichen der Verwendung der Ebene PUBLIC.

# Antipattern!
# This incorrectly allows any user to view all documents
query ListDocuments @auth(level: USER) {
  documents {
    id
    title
    text
  }
}

Verwenden Sie für das Prototyping nicht die Zugriffsebene PUBLIC oder USER.

Um die Entwicklung zu beschleunigen, kann es verlockend sein, alle Vorgänge auf die Zugriffsebene PUBLIC oder USER festzulegen, ohne weitere Verbesserungen vorzunehmen, um alle Vorgänge zu autorisieren und den Code schnell zu testen.

Nachdem Sie auf diese Weise die ersten Prototypen erstellt haben, sollten Sie von NO_ACCESS zu einer produktionsfertigen Autorisierung mit den Ebenen PUBLIC und USER wechseln. Sie sollten sie jedoch nicht als PUBLIC oder USER bereitstellen, ohne wie in diesem Leitfaden beschrieben zusätzliche Logik hinzuzufügen.

# Antipattern!
# This incorrectly allows anyone to delete any post
mutation DeletePost($id: UUID!) @auth(level: PUBLIC) {
  post: post_delete(
    id: $id,
  )
}

Firebase App Check für die App-Attestierung verwenden

Authentifizierung und Autorisierung sind wichtige Komponenten derData Connect Sicherheit. Authentifizierung und Autorisierung in Kombination mit App-Attestierung sorgen für eine sehr robuste Sicherheitslösung.

Bei der Attestierung über Firebase App Check verwenden Geräte, auf denen Ihre App ausgeführt wird, einen App- oder Geräteattestierungsanbieter, der bestätigt, dass Data Connect-Vorgänge von Ihrer authentischen App stammen und Anfragen von einem authentischen, nicht manipulierten Gerät stammen. Diese Attestierung ist jeder Anfrage Ihrer App an Data Connect angehängt.

Weitere Informationen zum Aktivieren von App Check für Data Connect und zum Einbinden des Client-SDKs in Ihre App finden Sie in der App Check-Übersicht.

Authentifizierungsebenen für die @auth(level)-Richtlinie

In der folgenden Tabelle sind alle Standardzugriffsebenen und ihre CEL-Entsprechungen aufgeführt. Die Authentifizierungsebenen sind von allgemein nach spezifisch aufgelistet. Jede Ebene umfasst alle Nutzer, die den folgenden Ebenen entsprechen.

Level Definition
PUBLIC Der Vorgang kann von jeder Person mit oder ohne Authentifizierung ausgeführt werden.

Hinweise:Daten können von allen Nutzern gelesen oder geändert werden. Firebase empfiehlt diese Autorisierungsebene für öffentlich zugängliche Daten wie Produkt- oder Medieneinträge. Best Practices und Alternativen

Entspricht @auth(expr: "true")

@auth-Filter und ‑Ausdrücke können mit dieser Zugriffsebene nicht verwendet werden. Solche Ausdrücke schlagen mit dem Fehler 400 Bad Request fehl.
USER_ANON Jeder identifizierte Nutzer, einschließlich derer, die sich mit Firebase Authentication anonym angemeldet haben, ist berechtigt, die Abfrage oder Mutation auszuführen.

Hinweis: USER_ANON ist ein Oberbegriff für USER.

Hinweise:Ihre Abfragen und Mutationen müssen für diese Autorisierungsebene sorgfältig konzipiert werden. Auf dieser Ebene können Nutzer anonym (automatische Anmeldung, die nur mit einem Nutzergerät verknüpft ist) mit Authentication angemeldet werden. Es werden keine anderen Prüfungen durchgeführt, z. B. ob die Daten dem Nutzer gehören. Best Practices und Alternativen

Da bei anonymen Anmeldeflüssen von Authentication eine uid ausgegeben wird, entspricht die USER_ANON-Ebene
@auth(expr: "auth.uid != nil").
USER Jeder Nutzer, der sich mit Firebase Authentication angemeldet hat, ist berechtigt, die Abfrage oder Mutation auszuführen, mit Ausnahme von Nutzern mit anonymer Anmeldung.

Hinweise:Ihre Abfragen und Mutationen müssen für diese Autorisierungsebene sorgfältig konzipiert werden. Auf dieser Ebene wird nur geprüft, ob der Nutzer mit Authentication angemeldet ist. Es werden keine anderen Prüfungen durchgeführt, z. B. ob die Daten dem Nutzer gehören. Best Practices und Alternativen

Entspricht @auth(expr: "auth.uid != nil && auth.token.firebase.sign_in_provider != 'anonymous'")"
USER_EMAIL_VERIFIED Jeder Nutzer, der sich mit Firebase Authentication und einer bestätigten E-Mail-Adresse angemeldet hat, ist berechtigt, die Abfrage oder Mutation auszuführen.

Hinweise:Da die E-Mail-Bestätigung mit Authentication durchgeführt wird, basiert sie auf einer robusteren Authentication-Methode. Daher bietet dieses Niveau im Vergleich zu USER oder USER_ANON zusätzliche Sicherheit. Auf dieser Ebene wird nur geprüft, ob der Nutzer mit einer bestätigten E-Mail-Adresse bei Authentication angemeldet ist. Es werden keine weiteren Prüfungen durchgeführt, z. B. ob die Daten dem Nutzer gehören. Best Practices und Alternativen

Entspricht @auth(expr: "auth.uid != nil && auth.token.email_verified")"
NO_ACCESS Dieser Vorgang kann nicht außerhalb eines Admin SDK-Kontexts ausgeführt werden.

Entspricht @auth(expr: "false")

CEL-Referenz für @auth(expr) und @check(expr)

Wie in den Beispielen an anderer Stelle in diesem Leitfaden gezeigt, können und sollten Sie Ausdrücke verwenden, die in der Common Expression Language (CEL) definiert sind, um die Autorisierung für Data Connect mithilfe von @auth(expr:)- und @check-Direktiven zu steuern.

In diesem Abschnitt wird die CEL-Syntax behandelt, die für das Erstellen von Ausdrücken für diese Anweisungen relevant ist.

Vollständige Referenzinformationen zu CEL finden Sie in der CEL-Spezifikation.

Testvariablen, die in Abfragen und Mutationen übergeben werden

Mit der @auth(expr)-Syntax können Sie auf Variablen aus Abfragen und Mutationen zugreifen und sie testen.

Sie können beispielsweise eine Vorgangsvariable wie $status mit vars.status einfügen.

mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")

Für Ausdrücke verfügbare Daten

Sowohl @auth(expr:) als auch @check(expr:) können CEL-Ausdrücke für Folgendes auswerten:

  • request.operationName
  • vars (Alias für request.variables)
  • auth (Alias für request.auth)

Außerdem können @check(expr:)-Ausdrücke Folgendes auswerten:

  • this (Wert des aktuellen Felds)

Das Objekt „request.operationName“

Im request.operarationName-Objekt wird der Vorgangstyp gespeichert, also „Abfrage“ oder „Mutation“.

Das vars-Objekt

Über das vars-Objekt können Ihre Ausdrücke auf alle Variablen zugreifen, die in Ihrer Abfrage oder Mutation übergeben wurden.

Sie können vars.<variablename> in einem Ausdruck als Alias für die vollständige request.variables.<variablename> verwenden:

# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")

Das auth-Objekt

Authentication identifiziert Nutzer, die Zugriff auf Ihre Daten anfordern, und stellt diese Informationen als Objekt bereit, auf das Sie in Ihren Ausdrücken aufbauen können.

In Ihren Filtern und Ausdrücken können Sie auth als Alias für request.auth verwenden.

Das Auth-Objekt enthält die folgenden Informationen:

  • uid: Eine eindeutige Nutzer-ID, die dem anfragenden Nutzer zugewiesen ist.
  • token: Eine Zuordnungstabelle der von Authentication erfassten Werte.

Weitere Informationen zum Inhalt von auth.token finden Sie unter Daten in Auth-Tokens.

Die this-Bindung

Die Bindung this wird auf das Feld angewendet, an das die Anweisung @check angehängt ist. In einem einfachen Fall können Sie Ergebnisse von Abfragen mit nur einem Wert auswerten.

mutation UpdateMovieTitle($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
  # Step 1: Query and check
  query @redact {
    moviePermission( # Look up a join table called MoviePermission with a compound key.
      key: {movieId: $movieId, userId_expr: "auth.uid"}
    ) {
      # Check if the user has the editor role for the movie. `this` is the string value of `role`.
      # If the parent moviePermission is null, the @check will also fail automatically.
      role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
    }
  }
  # Step 2: Act
  movie_update(id: $movieId, data: {
    title: $newTitle
  })
}

Wenn das zurückgegebene Feld mehrmals vorkommt, weil ein Vorfahr eine Liste ist, wird jedes Vorkommen mit this getestet, das an jeden Wert gebunden ist.

Wenn ein Vorfahr eines bestimmten Pfades null oder [] ist, wird das Feld nicht erreicht und die CEL-Bewertung für diesen Pfad übersprungen. Mit anderen Worten: Die Auswertung erfolgt nur, wenn this null oder nicht null ist, aber nie undefined.

Wenn das Feld selbst eine Liste oder ein Objekt ist, folgt this derselben Struktur (einschließlich aller ausgewählter Abkömmlinge bei Objekten), wie im folgenden Beispiel dargestellt.

mutation UpdateMovieTitle2($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
  # Step 1: Query and check
  query {
    moviePermissions( # Now we query for a list of all matching MoviePermissions.
      where: {movieId: {eq: $movieId}, userId: {eq_expr: "auth.uid"}}
    # This time we execute the @check on the list, so `this` is the list of objects.
    # We can use the `.exists` macro to check if there is at least one matching entry.
    ) @check(expr: "this.exists(p, p.role == 'editor')", message: "You must be an editor of this movie to update title") {
      role
    }
  }
  # Step 2: Act
  movie_update(id: $movieId, data: {
    title: $newTitle
  })
}

Syntax komplexer Ausdrücke

Sie können komplexere Ausdrücke formulieren, indem Sie sie mit den Operatoren && und || kombinieren.

mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")

Im folgenden Abschnitt werden alle verfügbaren Operatoren beschrieben.

Operatoren und Operatorrangfolge

In der folgenden Tabelle finden Sie eine Übersicht über die Operatoren und ihre jeweilige Priorität.

Es sind beliebige Ausdrücke a und b, ein Feld f und ein Index i gegeben.

Operator Beschreibung Assoziativität
a[i] a() a.f Index, Aufruf, Feldzugriff von links nach rechts
!a -a Unäre Negation von rechts nach links
a/b a%b a*b Multiplikative Operatoren von links nach rechts
a+b a-b Additivoperatoren von links nach rechts
a>b a>=b a<b a<=b Relationale Operatoren von links nach rechts
a in b Vorhandensein in Liste oder Karte von links nach rechts
type(a) == t Typvergleich, wobei t „bool“, „int“, „float“, „number“, „string“, „list“, „map“, „timestamp“ oder „duration“ sein kann von links nach rechts
a==b a!=b Vergleichsoperatoren von links nach rechts
a && b Bedingtes AND von links nach rechts
a || b Bedingtes ODER von links nach rechts
a ? true_value : false_value Ternärer Ausdruck von links nach rechts

Daten in Auth-Tokens

Das auth.token-Objekt kann die folgenden Werte enthalten:

Feld Beschreibung
email Die mit dem Konto verknüpfte E-Mail-Adresse, sofern vorhanden.
email_verified true, wenn der Nutzer bestätigt hat, dass er Zugriff auf die email-Adresse hat. Einige Anbieter bestätigen E-Mail-Adressen, die ihnen gehören, automatisch.
phone_number Die mit dem Konto verknüpfte Telefonnummer, falls vorhanden.
name Der Anzeigename des Nutzers, falls festgelegt.
sub Die Firebase-UID des Nutzers. Dieser Wert ist innerhalb eines Projekts eindeutig.
firebase.identities Wörterbuch aller Identitäten, die mit dem Konto dieses Nutzers verknüpft sind. Die Schlüssel des Wörterbuchs können einen der folgenden Werte haben: email, phone, google.com, facebook.com, github.com oder twitter.com. Die Werte des Wörterbuchs sind Arrays eindeutiger IDs für jeden Identitätsanbieter, der mit dem Konto verknüpft ist. auth.token.firebase.identities["google.com"][0] enthält beispielsweise die erste Google-Nutzer-ID, die mit dem Konto verknüpft ist.
firebase.sign_in_provider Der Anmeldeanbieter, der zum Abrufen dieses Tokens verwendet wurde. Kann einer der folgenden Strings sein: custom, password, phone, anonymous, google.com, facebook.com, github.com, twitter.com.
firebase.tenant Die mit dem Konto verknüpfte „tenantId“, falls vorhanden. Beispiel: tenant2-m6tyz

Zusätzliche Felder in JWT-ID-Tokens

Sie können auch auf die folgenden auth.token-Felder zugreifen:

Benutzerdefinierte Token-Anforderungen
alg Algorithmus "RS256"
iss Aussteller Die E-Mail-Adresse des Dienstkontos Ihres Projekts
sub Betreff Die E-Mail-Adresse des Dienstkontos Ihres Projekts
aud Zielgruppe "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Ausstellungszeit Die aktuelle Zeit in Sekunden seit der UNIX-Epoche
exp Ablaufzeit Die Zeit in Sekunden seit der UNIX-Epoche, zu der das Token abläuft. Dies kann maximal 3.600 Sekunden später als iat sein.
Beachten Sie, dass damit nur der Zeitpunkt gesteuert wird, zu dem das benutzerdefinierte Token selbst abläuft. Wenn Sie jedoch einen Nutzer mit signInWithCustomToken() anmelden, bleiben er so lange auf dem Gerät angemeldet, bis die Sitzung ungültig wird oder der Nutzer sich abmeldet.
<claims> (optional) Optionale benutzerdefinierte Ansprüche, die in das Token aufgenommen werden sollen. Auf diese kann in Ausdrücken über auth.token (oder request.auth.token) zugegriffen werden. Wenn du beispielsweise einen benutzerdefinierten Anspruch adminClaim erstellst, kannst du über auth.token.adminClaim darauf zugreifen.

Nächste Schritte