Ten przewodnik zawiera informacje o składni języka Common Expression Language (CEL) przydatne podczas tworzenia wyrażeń dla dyrektyw @auth(expr:) i @check(expr:).
Pełne informacje o języku 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 dla wyrażeń: request, response, this
Dane są używane do:
- oceny za pomocą wyrażeń CEL w dyrektywach
@auth(expr:)i@check(expr:); - przypisywania za pomocą wyrażeń serwera,
<field>_expr.
Wyrażenia CEL @auth(expr:) i @check(expr:) mogą oceniać te elementy:
request.operationNamevars(aliasrequest.variables)auth(aliasrequest.auth)
W mutacjach możesz uzyskiwać dostęp do treści tych elementów i przypisywać je:
response(aby sprawdzić wyniki częściowe w logice wieloetapowej).
Dodatkowo wyrażenia @check(expr:) mogą oceniać te elementy:
this(wartość bieżącego pola);response(aby sprawdzić wyniki częściowe w logice wieloetapowej).
Powiązanie request.operationName
Powiązanie request.operarationName przechowuje typ operacji, czyli zapytanie lub mutację.
Powiązanie vars (request.vars)
Powiązanie vars umożliwia wyrażeniom dostęp do wszystkich zmiennych przekazywanych w zapytaniu lub mutacji.
W wyrażeniu możesz użyć vars.<variablename> jako aliasu dla
pełnej nazwy 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 opierać się w swoich wyrażeniach.
W filtrach i wyrażeniach możesz używać auth jako aliasu dla
request.auth.
Powiązanie auth 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 uwierzytelniania
Powiązanie response
Powiązanie response zawiera dane gromadzone przez serwer w odpowiedzi na zapytanie lub mutację w trakcie ich gromadzenia.
W miarę postępu operacji i pomyślnego ukończenia każdego kroku powiązanie response zawiera dane odpowiedzi z pomyślnie ukończonych kroków.
Powiązanie response jest ustrukturyzowane zgodnie z kształtem powiązanej operacji, w tym (wieloma) zagnieżdżonymi polami i (w stosownych przypadkach) zapytaniami osadzonymi.
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 żądanych w zapytaniu osadzonym. Gdy uzyskujesz dostęp do danych zwracanych przez pola mutacji, takie jak _insert i _delete, mogą one
zawierać klucze UUID, liczbę usunięć, wartości null (patrz
dokumentacja mutacji).
Przykład:
- W mutacji, która zawiera zapytanie osadzone,
responsepowiązanie zawiera dane wyszukiwania wresponse.query.<fieldName>.<fieldName>...., w tym przypadkuresponse.query.todoListiresponse.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 mutacji wieloetapowej, na przykład z wieloma
_insertpolami, powiązanieresponsezawiera dane częściowe wresponse.<fieldName>.<fieldName>...., w tym przypadku,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,
})
}
Powiązanie this
Powiązanie this jest oceniane jako pole, do którego jest dołączona dyrektywa @check. W podstawowym przypadku możesz oceniać wyniki zapytań z jedną wartością.
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 zwracane pole występuje wiele razy, ponieważ dowolny element nadrzędny jest listą, każde wystąpienie jest testowane za pomocą powiązania this 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 odbywa się tylko wtedy, gdy this ma wartość null lub inną niż null, ale nigdy undefined.
Gdy pole jest listą lub obiektem, this ma taką samą strukturę (w tym wszystkie elementy podrzędne wybrane w przypadku obiektów), jak pokazano w tym przykładzie.
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 za pomocą && i ||
operatorów.
mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")
W sekcji poniżej znajdziesz opis wszystkich dostępnych operatorów.
Operatory i kolejność wykonywania operatorów
W tej tabeli znajdziesz informacje o operatorach i ich kolejności wykonywania.
Dane są dowolnymi wyrażeniami a i b, polem f oraz indeksem i.
| Operator | Opis | Łączność |
|---|---|---|
a[i] a() a.f |
Indeks, wywołanie, dostęp do pola | 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 |
Istnienie na liście lub w mapie | od lewej do prawej |
type(a) == t |
Porównanie typu, 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 |
Warunkowy operator AND | od lewej do prawej |
a || b |
Warunkowy operator OR | 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 użytkownika w Firebase. 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 to być jeden z tych ciągów znaków: custom, password, phone, anonymous, google.com, facebook.com, github.com, twitter.com. |
firebase.tenant |
Identyfikator tenantId powiązany z kontem, jeśli jest dostępny. Na przykład tenant2-m6tyz. |
Dodatkowe pola w tokenach tożsamości JWT
Możesz też uzyskać dostęp do tych pól auth.token:
| Niestandardowe deklaracje tokena | ||
|---|---|---|
alg |
Algorytm | "RS256" |
iss |
Wystawca | Adres e-mail konta usługi projektu |
sub |
Temat | Adres e-mail konta usługi projektu |
aud |
Odbiorcy | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
Godzina wystawienia | Aktualny czas w sekundach od początku epoki UNIX |
exp |
Data ważności |
Czas w sekundach od początku epoki UNIX, w którym token wygasa. Może to być
maksymalnie 3600 sekund później niż iat.
Uwaga: ta wartość określa tylko czas wygaśnięcia tokena niestandardowego samego tokena. Gdy jednak zalogujesz użytkownika za pomocą signInWithCustomToken(), pozostanie on zalogowany na
urządzeniu, dopóki jego sesja nie zostanie unieważniona lub użytkownik się nie wyloguje.
|
<claims> (opcjonalnie) |
Opcjonalne deklaracje niestandardowe, które mają być uwzględnione w tokenie. Można uzyskać do nich dostęp za pomocą
auth.token (lub request.auth.token) w
wyrażeniach. Jeśli na przykład utworzysz deklarację niestandardową
adminClaim, możesz uzyskać do niej dostęp za pomocą
auth.token.adminClaim.
|
|