本參考指南涵蓋與為 @auth(expr:) 和 @check(expr:) 指令建立運算式相關的一般運算語言 (CEL) 語法。
如需完整的 CEL 參考資訊,請參閱 CEL 規格。
在查詢和突變中傳遞的測試變數
@auth(expr) 語法可讓您存取及測試查詢和變異中的變數。
舉例來說,您可以使用 vars.status 納入作業變數,例如 $status。
mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")
運算式可用的資料:要求、回應、this
資料的用途包括:
- 在
@auth(expr:)和@check(expr:)指令中,使用 CEL 運算式進行評估 - 使用伺服器運算式指派,
<field>_expr。
@auth(expr:) 和 @check(expr:) CEL 運算式都可以評估下列項目:
request.operationNamevars(request.variables的別名)auth(request.auth的別名)
在突變中,您可以存取及指派下列內容:
response(檢查多步驟邏輯中的部分結果)
此外,@check(expr:) 運算式可以評估:
this(目前欄位的值)response(檢查多步驟邏輯中的部分結果)
request.operationName 繫結
request.operarationName 繫結會儲存作業類型,可以是查詢或變異。
vars繫結 (request.vars)
vars 繫結可讓運算式存取查詢或變異中傳遞的所有變數。
您可以在運算式中使用 vars.<variablename> 做為完整 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'")
auth 繫結 (request.auth)
Authentication 會識別要求存取您資料的使用者,並提供該資訊做為繫結,您可以在運算式中建構該繫結。
在篩選器和運算式中,您可以使用 auth 做為 request.auth 的別名。
授權繫結包含下列資訊:
uid:指派給要求者的專屬使用者 ID。token:由 Authentication 收集的值對應表。
如要進一步瞭解 auth.token 的內容,請參閱「授權權杖中的資料」。
response 繫結
response 繫結包含伺服器在回應查詢或變動時組裝的資料,因為這些資料正在組裝中。
作業進行期間,每當成功完成一個步驟,response 就會包含成功完成步驟的回應資料。
response 繫結的結構會根據相關聯作業的形狀而定,包括 (多個) 巢狀欄位和 (如適用) 內嵌查詢。
請注意,存取嵌入式查詢回應資料時,欄位可能包含任何資料類型,視嵌入式查詢中要求的資料而定;存取突變欄位 (例如 _insert 和 _delete) 傳回的資料時,這些欄位可能包含 UUID 鍵、刪除次數和空值 (請參閱突變參考資料)。
例如:
- 在含有內嵌查詢的突變中,繫結會在
response.query.<fieldName>.<fieldName>....包含查詢資料,在本例中為response.query.todoList和response.query.todoList.priority。response
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
}
}
}
- 舉例來說,在多步驟變動中 (例如有多個
_insert欄位),response繫結會在response.<fieldName>.<fieldName>....包含部分資料,在本例中為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,
})
}
this 繫結
繫結 this 會評估 @check 指令所附加的欄位。在基本情況下,您可能會評估單一值的查詢結果。
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
})
}
如果任何祖先是清單,傳回的欄位就會多次出現,每次出現時,系統都會使用繫結至每個值的 this 進行測試。
對於任何指定路徑,如果祖先是 null 或 [],系統就不會抵達該欄位,並會略過該路徑的 CEL 評估。換句話說,只有在 this 為 null 或非 null 時,才會進行評估,但絕不會是 undefined。
如果欄位本身是清單或物件,this 會遵循相同的結構 (包括物件中選取的所有子項),如下例所示。
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
})
}
複雜運算式語法
您可以結合 && 和 || 運算子,編寫更複雜的運算式。
mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")
以下章節說明所有可用的運算子。
運算子和運算子優先順序
請參考下表,瞭解運算子及其對應的優先順序。
假設有任意運算式 a 和 b、欄位 f 和索引 i。
| 運算子 | 說明 | 結合性 |
|---|---|---|
a[i] a() a.f |
索引、呼叫、欄位存取權 | 從左到右 |
!a -a |
一元否定 | 由右至左 |
a/b a%b a*b |
乘法運算子 | 從左到右 |
a+b a-b |
加法運算子 | 從左到右 |
a>b a>=b a<b a<=b |
關係運算子 | 從左到右 |
a in b |
是否列於清單或地圖中 | 從左到右 |
type(a) == t |
類型比較,其中 t 可以是 bool、int、float、數字、字串、清單、對應、時間戳記或時間長度 |
從左到右 |
a==b a!=b |
比較運算子 | 從左到右 |
a && b |
條件式 AND | 從左到右 |
a || b |
條件式 OR | 從左到右 |
a ? true_value : false_value |
三元運算式 | 從左到右 |
驗證權杖中的資料
auth.token 物件可能包含下列值:
| 欄位 | 說明 |
|---|---|
email |
與帳戶相關聯的電子郵件地址 (如有)。 |
email_verified |
true,前提是使用者已驗證自己有權存取 email 地址。部分供應商會自動驗證他們擁有的電子郵件地址。 |
phone_number |
與帳戶相關聯的電話號碼 (如有)。 |
name |
使用者的顯示名稱 (如有設定)。 |
sub |
使用者的 Firebase UID。這項 ID 在專案中不得重複。 |
firebase.identities |
與這個使用者帳戶相關聯的所有身分識別字典。字典的鍵可以是下列任一項:email、phone、google.com、facebook.com、github.com、twitter.com。字典的值是與帳戶相關聯的每個身分識別提供者的專屬 ID 陣列。舉例來說,auth.token.firebase.identities["google.com"][0] 包含與帳戶相關聯的第一個 Google 使用者 ID。 |
firebase.sign_in_provider |
用來取得這個權杖的登入資訊提供者。可以是下列任一字串:custom、password、phone、anonymous、google.com、facebook.com、github.com、twitter.com。 |
firebase.tenant |
與帳戶相關聯的 tenantId (如有)。例如 tenant2-m6tyz。 |
JWT ID 權杖中的其他欄位
您也可以存取下列 auth.token 欄位:
| 自訂權杖聲明 | ||
|---|---|---|
alg |
演算法 | "RS256" |
iss |
核發單位 | 專案的服務帳戶電子郵件地址 |
sub |
主旨 | 專案的服務帳戶電子郵件地址 |
aud |
目標對象 | "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit" |
iat |
核發時間 | 目前時間,以 UNIX Epoch 紀元時間為始 (單位為秒) |
exp |
到期時間 |
權杖到期時間,以秒為單位,自 UNIX Epoch 紀元時間開始算起。iat 最多可延後 3600 秒。注意:這項設定只會控管自訂權杖本身的到期時間,不過,一旦您使用 signInWithCustomToken() 登入使用者,他們就會保持登入裝置的狀態,直到工作階段失效或使用者登出為止。 |
<claims> (選填) |
要在權杖中加入的選用自訂聲明,可透過運算式中的 auth.token (或 request.auth.token) 存取。舉例來說,如果您建立自訂聲明 adminClaim,可以使用 auth.token.adminClaim 存取該聲明。 |
|