Ce guide de référence couvre la syntaxe CEL (Common Expression Language) pertinente pour créer des expressions pour les directives @auth(expr:)
et @check(expr:)
.
Vous trouverez des informations de référence complètes sur CEL dans la spécification CEL.
Tester les variables transmises dans les requêtes et les mutations
La syntaxe @auth(expr)
vous permet d'accéder aux variables des requêtes et des mutations, et de les tester.
Par exemple, vous pouvez inclure une variable d'opération, telle que $status
, à l'aide de vars.status
.
mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")
Données disponibles pour les expressions : request, response, this
Vous utilisez les données pour :
- Évaluation avec des expressions CEL dans les directives
@auth(expr:)
et@check(expr:)
- Attribution à l'aide d'expressions de serveur,
<field>_expr
.
Les expressions CEL @auth(expr:)
et @check(expr:)
peuvent évaluer les éléments suivants :
request.operationName
vars
(alias derequest.variables
)auth
(alias derequest.auth
)
Dans les mutations, vous pouvez accéder au contenu des éléments suivants et l'attribuer :
response
(pour vérifier les résultats partiels dans une logique en plusieurs étapes)
De plus, les expressions @check(expr:)
peuvent évaluer :
this
(valeur du champ actuel)response
(pour vérifier les résultats partiels dans la logique en plusieurs étapes)
Liaison request.operationName
La liaison request.operarationName
stocke le type d'opération, qu'il s'agisse d'une requête ou d'une mutation.
L'association vars
(request.vars)
La liaison vars
permet à vos expressions d'accéder à toutes les variables transmises dans votre requête ou mutation.
Vous pouvez utiliser vars.<variablename>
dans une expression comme alias pour request.variables.<variablename>
complet :
# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")
Liaison auth
(request.auth)
Authentication identifie les utilisateurs qui demandent l'accès à vos données et fournit ces informations sous la forme d'une liaison sur laquelle vous pouvez vous appuyer dans vos expressions.
Dans vos filtres et expressions, vous pouvez utiliser auth
comme alias pour request.auth
.
La liaison d'authentification contient les informations suivantes :
uid
: ID utilisateur unique attribué à l'utilisateur qui effectue la requête.token
: carte des valeurs collectées par Authentication.
Pour en savoir plus sur le contenu de auth.token
, consultez Données dans les jetons d'authentification.
Liaison response
La liaison response
contient les données assemblées par le serveur en réponse à une requête ou à une mutation au fur et à mesure de leur assemblage.
Au fur et à mesure de l'opération, à chaque étape terminée avec succès, response
contient les données de réponse des étapes terminées avec succès.
La liaison response
est structurée en fonction de la forme de son opération associée, y compris les champs imbriqués (multiples) et les requêtes intégrées (le cas échéant).
Notez que lorsque vous accédez aux données de réponse aux requêtes intégrées, les champs peuvent contenir n'importe quel type de données, en fonction des données demandées dans la requête intégrée. Lorsque vous accédez aux données renvoyées par les champs de mutation tels que _insert
et _delete
, ils peuvent contenir des clés UUID, le nombre de suppressions ou des valeurs nulles (consultez la documentation sur les mutations).
Exemple :
- Dans une mutation contenant une requête intégrée, la liaison
response
contient des données de recherche àresponse.query.<fieldName>.<fieldName>....
, dans ce cas,response.query.todoList
etresponse.query.todoList.priority
.
mutation CheckTodoPriority(
$uniqueListName: String!
) {
# This query is identified as `response.query`
query @check(expr: "response.query.todoList.priority == 'high'", message: "This list is not for high priority items!") {
# This field is identified as `response.query.todoList`
todoList(where: { name: $uniqueListName }) {
# This field is identified as `response.query.todoList.priority`
priority
}
}
}
- Dans une mutation en plusieurs étapes, par exemple avec plusieurs champs
_insert
, la liaisonresponse
contient des données partielles àresponse.<fieldName>.<fieldName>....
, dans ce cas,response.todoList_insert.id
.
mutation CreateTodoListWithFirstItem(
$listName: String!,
$itemContent: String!
) @transaction {
# Step 1
todoList_insert(data: {
id_expr: "uuidV4()",
name: $listName,
})
# Step 2:
todo_insert(data: {
listId_expr: "response.todoList_insert.id" # <-- Grab the newly generated ID from the partial response so far.
content: $itemContent,
})
}
Liaison this
La liaison this
est évaluée par rapport au champ auquel la directive @check
est associée. Dans un cas de base, vous pouvez évaluer les résultats de requêtes à valeur unique.
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
})
}
Si le champ renvoyé se produit plusieurs fois parce qu'un ancêtre est une liste, chaque occurrence est testée avec this
lié à chaque valeur.
Pour n'importe quel chemin d'accès, si un ancêtre est null
ou []
, le champ ne sera pas atteint et l'évaluation CEL sera ignorée pour ce chemin d'accès. En d'autres termes, l'évaluation n'a lieu que lorsque this
est null
ou non null
, mais jamais undefined
.
Lorsque le champ lui-même est une liste ou un objet, this
suit la même structure (y compris tous les descendants sélectionnés en cas d'objets), comme illustré dans l'exemple suivant.
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
})
}
Syntaxe des expressions complexes
Vous pouvez écrire des expressions plus complexes en les combinant avec les opérateurs &&
et ||
.
mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")
La section suivante décrit tous les opérateurs disponibles.
Opérateurs et priorité des opérateurs
Utilisez le tableau suivant comme référence pour les opérateurs et leur priorité correspondante.
Étant donné des expressions arbitraires a
et b
, un champ f
et un index i
.
Opérateur | Description | Associativité |
---|---|---|
a[i] a() a.f |
Index, appel, accès aux champs | de gauche à droite. |
!a -a |
Négation unaire | de droite à gauche |
a/b a%b a*b |
Opérateurs multiplicatifs | de gauche à droite. |
a+b a-b |
Opérateurs additifs | de gauche à droite. |
a>b a>=b a<b a<=b |
Opérateurs relationnels | de gauche à droite. |
a in b |
Présence dans une liste ou sur une carte | de gauche à droite. |
type(a) == t |
Comparaison de types, où t peut être bool, int, float, number, string, list, map, timestamp ou duration |
de gauche à droite. |
a==b a!=b |
Opérateurs de comparaison | de gauche à droite. |
a && b |
AND conditionnel | de gauche à droite. |
a || b |
OR conditionnel | de gauche à droite. |
a ? true_value : false_value |
Expression ternaire | de gauche à droite. |
Données dans les jetons d'authentification
L'objet auth.token
peut contenir les valeurs suivantes :
Champ | Description |
---|---|
email |
Adresse e-mail associée au compte, le cas échéant. |
email_verified |
true si l'utilisateur a confirmé avoir accès à l'adresse email . Certains fournisseurs valident automatiquement les adresses e-mail qu'ils possèdent. |
phone_number |
Numéro de téléphone associé au compte, le cas échéant. |
name |
Nom à afficher de l'utilisateur, s'il est défini. |
sub |
ID utilisateur Firebase de l'utilisateur. Il est unique dans un projet. |
firebase.identities |
Dictionnaire de toutes les identités associées au compte de cet utilisateur. Les clés du dictionnaire peuvent être l'une des suivantes : email , phone , google.com , facebook.com , github.com , twitter.com . Les valeurs du dictionnaire sont des tableaux d'identifiants uniques pour chaque fournisseur d'identité associé au compte. Par exemple, auth.token.firebase.identities["google.com"][0] contient le premier ID utilisateur Google associé au compte. |
firebase.sign_in_provider |
Fournisseur de connexion utilisé pour obtenir ce jeton. Peut être l'une des chaînes suivantes : custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com . |
firebase.tenant |
ID du locataire associé au compte, le cas échéant. Par exemple : tenant2-m6tyz |
Champs supplémentaires dans les jetons d'identité JWT
Vous pouvez également accéder aux champs auth.token
suivants :
Revendications de jetons personnalisées | ||
---|---|---|
alg |
Algorithme | "RS256" |
iss |
Émetteur | Adresse e-mail du compte de service de votre projet |
sub |
Objet | Adresse e-mail du compte de service de votre projet |
aud |
Public visé | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
Date/Heure d'émission | Heure actuelle, en secondes, depuis l'epoch UNIX |
exp |
Date/Heure d'expiration |
Durée, en secondes depuis l'époque UNIX, au bout de laquelle le jeton expire. Cette valeur peut correspondre à un maximum de 3 600 secondes après l'heure iat .
Remarque : Cette valeur ne contrôle que l'heure d'expiration du jeton personnalisé lui-même. Cependant, une fois que l'utilisateur est connecté à l'aide de signInWithCustomToken() , il reste connecté à l'appareil jusqu'à ce que sa session soit invalide ou qu'il se déconnecte.
|
<claims> (facultatif) |
Revendications personnalisées facultatives à inclure dans le jeton, accessibles via auth.token (ou request.auth.token ) dans les expressions. Par exemple, si vous créez une revendication personnalisée adminClaim , vous pouvez y accéder avec auth.token.adminClaim .
|