Este guia de referência aborda a sintaxe da Common Expression Language (CEL) relevante para
criar expressões para as diretivas @auth(expr:)
e @check(expr:)
.
As informações de referência completas da CEL estão disponíveis na especificação da CEL.
Testar variáveis transmitidas em consultas e mutações
A sintaxe @auth(expr)
permite acessar e testar variáveis de consultas e mutações.
Por exemplo, é possível incluir uma variável de operação, como $status
, usando
vars.status
.
mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")
Dados disponíveis para expressões: request, response, this
Você usa dados para:
- Avaliação com expressões CEL nas diretivas
@auth(expr:)
e@check(expr:)
- Atribuição usando expressões de servidor,
<field>_expr
.
As expressões CEL @auth(expr:)
e @check(expr:)
podem avaliar o seguinte:
request.operationName
vars
(alias derequest.variables
)auth
(alias derequest.auth
)
Nas mutações, é possível acessar e atribuir o conteúdo de:
response
(para verificar resultados parciais em uma lógica de várias etapas)
Além disso, as expressões @check(expr:)
podem avaliar:
this
(o valor do campo atual)response
(para verificar resultados parciais em uma lógica de várias etapas)
A vinculação request.operationName
A vinculação request.operarationName
armazena o tipo de operação, consulta ou mutação.
A vinculação vars
(request.vars)
A vinculação vars
permite que suas expressões acessem todas as variáveis
transmitidas na consulta ou mutação.
Você pode usar vars.<variablename>
em uma expressão como um alias para o
request.variables.<variablename>
totalmente qualificado:
# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")
A vinculação auth
(request.auth)
O Authentication identifica os usuários que solicitam acesso aos seus dados e fornece essas informações como uma vinculação que pode ser usada nas suas expressões.
Nos filtros e expressões, é possível usar auth
como um alias para request.auth
.
A vinculação de autenticação contém as seguintes informações:
uid
: um ID de usuário exclusivo, atribuído ao usuário solicitante.token
: um mapa de valores coletados por Authentication.
Para mais detalhes sobre o conteúdo de auth.token
, consulte
Dados em tokens de autenticação
A vinculação response
A vinculação response
contém os dados que estão sendo montados pelo servidor em
resposta a uma consulta ou mutação à medida que esses dados são montados.
À medida que a operação avança e cada etapa é concluída com sucesso, response
contém dados de resposta das etapas concluídas.
A vinculação response
é estruturada de acordo com a forma da operação associada, incluindo campos aninhados (múltiplos) e consultas incorporadas (se aplicável).
Ao acessar dados de resposta de consulta incorporada, os campos podem conter qualquer tipo de dado, dependendo dos dados solicitados na consulta incorporada. Ao acessar dados retornados por campos de mutação, como _insert
s e _delete
s, eles podem conter chaves UUID, número de exclusões, nulos. Consulte a referência de mutações.
Exemplo:
- Em uma mutação que contém uma consulta incorporada, a vinculação
response
contém dados de pesquisa emresponse.query.<fieldName>.<fieldName>....
, neste caso,response.query.todoList
eresponse.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
}
}
}
- Em uma mutação de várias etapas, por exemplo, com vários campos
_insert
, a vinculaçãoresponse
contém dados parciais emresponse.<fieldName>.<fieldName>....
, neste caso,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,
})
}
A vinculação this
A vinculação this
é avaliada como o campo a que a diretiva @check
está anexada. Em um caso básico, você pode avaliar resultados de consultas de valor único.
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
})
}
Se o campo retornado ocorrer várias vezes porque um ancestral é uma lista, cada
ocorrência será testada com this
vinculada a cada valor.
Para qualquer caminho, se um ancestral for null
ou []
, o campo não será alcançado e a avaliação do CEL será ignorada para esse caminho. Em outras palavras, a avaliação só acontece quando this
é null
ou não null
, mas nunca undefined
.
Quando o campo é uma lista ou um objeto, this
segue a mesma estrutura (incluindo todos os descendentes selecionados no caso de objetos), conforme ilustrado no exemplo a seguir.
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
})
}
Sintaxe de expressão complexa
É possível escrever expressões mais complexas combinando com os operadores &&
e ||
.
mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")
A seção a seguir descreve todos os operadores disponíveis.
Operadores e precedência do operador
Use a tabela a seguir como referência para os operadores e a precedência correspondente deles.
Expressões arbitrárias fornecidas a
e b
, um campo f
e um índice i
.
Operador | Descrição | Associatividade |
---|---|---|
a[i] a() a.f |
Índice, chamada, acesso ao campo | da esquerda para a direita |
!a -a |
Negação unária | da direita para a esquerda |
a/b a%b a*b |
Operadores multiplicativos | da esquerda para a direita |
a+b a-b |
Operadores aditivos | da esquerda para a direita |
a>b a>=b a<b a<=b |
Operadores relacionais | da esquerda para a direita |
a in b |
Existência na lista ou no mapa | da esquerda para a direita |
type(a) == t |
Comparação de tipos, em que t pode ser bool, int, float,
number, string, list, map, timestamp ou duration |
da esquerda para a direita |
a==b a!=b |
Operadores de comparação | da esquerda para a direita |
a && b |
Condicional E | da esquerda para a direita |
a || b |
Condicional OU | da esquerda para a direita |
a ? true_value : false_value |
Expressão ternária | da esquerda para a direita |
Dados em tokens de autenticação
O objeto auth.token
pode conter os seguintes valores:
Campo | Descrição |
---|---|
email |
O endereço de e-mail associado à conta, se essa informação existir. |
email_verified |
true se o usuário tiver verificado que tem acesso ao endereço email . Alguns provedores verificam automaticamente esses endereços de e-mail. |
phone_number |
O número de telefone associado à conta, se essa informação existir. |
name |
O nome de exibição do usuário, se ele tiver sido definido. |
sub |
O UID do Firebase do usuário. Ele é exclusivo dentro de um projeto. |
firebase.identities |
O dicionário de todas as identidades associadas à conta desse usuário. As chaves do dicionário podem ser qualquer uma das seguintes: email , phone , google.com , facebook.com , github.com , twitter.com . Os valores do dicionário são matrizes de identificadores exclusivos de cada provedor de identidade associado à conta. Por exemplo, auth.token.firebase.identities["google.com"][0] contém o primeiro ID de usuário do Google associado à conta. |
firebase.sign_in_provider |
O provedor de entrada usado para receber esse token. Pode ser uma das seguintes strings: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com . |
firebase.tenant |
O tenantId associado à conta, se houver. Por exemplo, tenant2-m6tyz . |
Campos adicionais em tokens de ID JWT
Você também pode acessar os seguintes campos auth.token
:
Declarações de tokens personalizados | ||
---|---|---|
alg |
Algoritmo | "RS256" |
iss |
Emissor | Endereço de e-mail da conta de serviço do seu projeto |
sub |
Assunto | Endereço de e-mail da conta de serviço do seu projeto |
aud |
Público | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
Hora de emissão | A hora atual, em segundos, desde a época do UNIX |
exp |
Tempo de expiração |
O tempo, em segundos, desde a época do UNIX, em que o token expira. Pode ser no máximo 3.600 segundos depois de iat .
Observação: ele controla o tempo apenas quando o token personalizado expira. No entanto, quando você faz o login de um usuário utilizando signInWithCustomToken() , ele permanece conectado ao
dispositivo até que a sessão seja invalidada ou que o usuário se desconecte.
|
<claims> (opcional) |
Declarações personalizadas opcionais a serem incluídas no token, que podem ser acessadas por
auth.token (ou request.auth.token ) em
expressões. Por exemplo, se você criar uma declaração personalizada
adminClaim , poderá acessá-la com
auth.token.adminClaim .
|