Ten przewodnik zawiera składnię języka Common Expression Language (CEL) związaną z tworzeniem wyrażeń dla dyrektyw @auth(expr:)
i @check(expr:)
.
Pełne informacje referencyjne dotyczące CEL znajdziesz w specyfikacji CEL.
Testowanie zmiennych przekazywanych w zapytaniach i mutacjach
Składnia @auth(expr)
umożliwia dostęp do zmiennych z zapytań i mutacji oraz ich testowanie.
Możesz na przykład uwzględnić zmienną operacji, np. $status
, używając vars.status
.
mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")
Dane dostępne w wyrażeniach: request, response, this
Dane są wykorzystywane do:
- Ocena za pomocą wyrażeń CEL w dyrektywach
@auth(expr:)
i@check(expr:)
- Przypisanie za pomocą wyrażeń serwera,
<field>_expr
.
Wyrażenia CEL @auth(expr:)
i @check(expr:)
mogą oceniać te elementy:
request.operationName
vars
(alias dlarequest.variables
)auth
(alias dlarequest.auth
)
W mutacjach możesz uzyskać dostęp do zawartości tych elementów i przypisać ją do nich:
response
(aby sprawdzić wyniki częściowe w logice wieloetapowej)
Dodatkowo wyrażenia @check(expr:)
mogą sprawdzać:
this
(wartość bieżącego pola)response
(aby sprawdzić wyniki częściowe w logice wieloetapowej)
Powiązanie request.operationName
Wiązanie request.operarationName
przechowuje typ operacji, czyli zapytanie lub zmianę.
Powiązanie vars
(request.vars)
Wiązanie vars
umożliwia wyrażeniom dostęp do wszystkich zmiennych przekazywanych w zapytaniu lub mutacji.
W wyrażeniu możesz użyć atrybutu vars.<variablename>
jako aliasu dla w pełni kwalifikowanego atrybutu request.variables.<variablename>
:
# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")
Powiązanie auth
(request.auth)
Authentication identyfikuje użytkowników, którzy proszą o dostęp do Twoich danych, i udostępnia te informacje jako powiązanie, na którym możesz budować wyrażenia.
W filtrach i wyrażeniach możesz używać znaku auth
jako aliasu dla request.auth
.
Powiązanie autoryzacji zawiera te informacje:
uid
: unikalny identyfikator użytkownika przypisany do użytkownika wysyłającego żądanie.token
: mapa wartości zebranych przez Authentication.
Więcej informacji o zawartości auth.token
znajdziesz w sekcji Dane w tokenach uwierzytelniających.
Powiązanie response
response
powiązanie zawiera dane, które serwer gromadzi w odpowiedzi na zapytanie lub mutację w trakcie ich gromadzenia.
W miarę postępu operacji, po pomyślnym zakończeniu każdego kroku, pole response
zawiera dane odpowiedzi z pomyślnie zakończonych kroków.
Powiązanie response
jest skonstruowane zgodnie z kształtem powiązanej operacji, w tym (wieloma) zagnieżdżonymi polami i (w stosownych przypadkach) wbudowanymi zapytaniami.
Pamiętaj, że gdy uzyskujesz dostęp do danych odpowiedzi na zapytanie osadzone, pola mogą zawierać dowolny typ danych w zależności od danych, o które prosisz w zapytaniu osadzonym. Gdy uzyskujesz dostęp do danych zwracanych przez pola mutacji, takie jak _insert
s i _delete
s, mogą one zawierać klucze UUID, liczbę usunięć i wartości null (patrz dokumentacja mutacji).
Przykład:
- W mutacji zawierającej zapytanie zagnieżdżone powiązanie
response
zawiera dane wyszukiwania wresponse.query.<fieldName>.<fieldName>....
, w tym przypadkuresponse.query.todoList
iresponse.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
}
}
}
- W przypadku mutacji wieloetapowej, na przykład z wieloma polami
_insert
, powiązanieresponse
zawiera częściowe dane w poluresponse.<fieldName>.<fieldName>....
, w tym przypadkuresponse.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,
})
}
Powiązanie this
Powiązanie this
jest obliczane na podstawie pola, do którego jest dołączona dyrektywa @check
. W podstawowym przypadku możesz oceniać wyniki zapytań jednowartościowych.
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
})
}
Jeśli zwrócone pole występuje wiele razy, ponieważ dowolny element nadrzędny jest listą, każde wystąpienie jest testowane z parametrem this
powiązanym z każdą wartością.
Jeśli w przypadku danej ścieżki element nadrzędny ma wartość null
lub []
, pole nie zostanie osiągnięte, a ocena CEL zostanie pominięta w przypadku tej ścieżki. Innymi słowy, ocena jest przeprowadzana tylko wtedy, gdy wartość this
to null
lub wartość niebędąca null
, ale nigdy undefined
.
Jeśli pole jest listą lub obiektem, this
ma taką samą strukturę (w przypadku obiektów obejmuje wszystkie wybrane elementy podrzędne), jak pokazano w przykładzie poniżej.
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
})
}
Składnia złożonych wyrażeń
Możesz pisać bardziej złożone wyrażenia, łącząc je z operatorami &&
i ||
.
mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")
W sekcji poniżej znajdziesz opis wszystkich dostępnych operatorów.
Operatory i ich kolejność
W poniższej tabeli znajdziesz operatory i ich priorytety.
Dane są wyrażeniami a
i b
, polem f
oraz indeksem i
.
Operator | Opis | Łączność |
---|---|---|
a[i] a() a.f |
Indeksowanie, wywoływanie, dostęp do pól | od lewej do prawej, |
!a -a |
Negacja jednoargumentowa | od prawej do lewej, |
a/b a%b a*b |
Operatory mnożenia | od lewej do prawej, |
a+b a-b |
Operatory dodawania | od lewej do prawej, |
a>b a>=b a<b a<=b |
Operatory relacji | od lewej do prawej, |
a in b |
Obecność na liście lub mapie | od lewej do prawej, |
type(a) == t |
porównanie typów, gdzie t może być wartością logiczną, liczbą całkowitą, liczbą zmiennoprzecinkową, liczbą, ciągiem znaków, listą, mapą, sygnaturą czasową lub czasem trwania; |
od lewej do prawej, |
a==b a!=b |
Operatory porównania | od lewej do prawej, |
a && b |
Warunkowe ORAZ | od lewej do prawej, |
a || b |
Warunkowe LUB | od lewej do prawej, |
a ? true_value : false_value |
Wyrażenie trójargumentowe | od lewej do prawej, |
Dane w tokenach uwierzytelniania
Obiekt auth.token
może zawierać te wartości:
Pole | Opis |
---|---|
email |
adres e-mail powiązany z kontem (jeśli jest dostępny); |
email_verified |
true , jeśli użytkownik potwierdził, że ma dostęp do adresu email . Niektórzy dostawcy automatycznie weryfikują adresy e-mail, których są właścicielami. |
phone_number |
numer telefonu powiązany z kontem (jeśli jest dostępny); |
name |
Wyświetlana nazwa użytkownika, jeśli została ustawiona. |
sub |
Identyfikator UID Firebase użytkownika. Jest on unikalny w obrębie projektu. |
firebase.identities |
Słownik wszystkich tożsamości powiązanych z kontem tego użytkownika. Klucze słownika mogą być dowolne z tych wartości: email , phone , google.com , facebook.com , github.com , twitter.com . Wartości słownika to tablice unikalnych identyfikatorów każdego dostawcy tożsamości powiązanego z kontem. Na przykład auth.token.firebase.identities["google.com"][0] zawiera pierwszy identyfikator użytkownika Google powiązany z kontem. |
firebase.sign_in_provider |
Dostawca logowania użyty do uzyskania tego tokena. Może być jednym z tych ciągów: custom , password , phone , anonymous , google.com , facebook.com , github.com , twitter.com . |
firebase.tenant |
Identyfikator tenantId powiązany z kontem (jeśli występuje). Na przykład tenant2-m6tyz |
Dodatkowe pola w tokenach identyfikatorów JWT
Możesz też uzyskać dostęp do tych pól auth.token
:
Deklaracje tokenów niestandardowych | ||
---|---|---|
alg |
Algorytm | "RS256" |
iss |
Wystawca | Adres e-mail konta usługi w projekcie |
sub |
Temat | Adres e-mail konta usługi w projekcie |
aud |
Odbiorcy | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
Godzina wydania | Bieżący czas w sekundach od początku epoki systemu UNIX. |
exp |
Okres ważności |
Czas wygaśnięcia tokena podany w sekundach od początku epoki systemu UNIX. Może być maksymalnie o 3600 sekund późniejsza niż wartość iat .
Uwaga: to ustawienie kontroluje tylko czas wygaśnięcia samego tokena niestandardowego. Gdy jednak zalogujesz użytkownika za pomocą signInWithCustomToken() , pozostanie on zalogowany na urządzeniu, dopóki jego sesja nie straci ważności lub użytkownik się nie wyloguje.
|
<claims> (opcjonalnie) |
Opcjonalne roszczenia niestandardowe do uwzględnienia w tokenie, do których można uzyskać dostęp za pomocą symbolu auth.token (lub request.auth.token ) w wyrażeniach. Jeśli na przykład utworzysz roszczenie niestandardowe adminClaim , możesz uzyskać do niego dostęp za pomocą auth.token.adminClaim .
|