Firebase Data Connect 提供強大的用戶端安全防護,包括:
- 行動和網路用戶端授權
- 個別查詢和變動層級的授權控管
- 使用 Firebase App Check 進行應用程式認證。
Data Connect 透過下列方式擴展這項安全性:
- 伺服器端授權
- 透過 IAM 保護 Firebase 專案和 Cloud SQL 使用者安全。
授權用戶端查詢和變動
Data Connect 與 Firebase Authentication 完全整合,因此您可以在設計中,使用存取資料的使用者相關豐富資料 (驗證),決定這些使用者可存取哪些資料 (授權)。
Data Connect 為查詢和變動提供 @auth
指令,可讓您設定授權作業所需的驗證層級。本指南會介紹 @auth
指令,並提供範例。
此外,Data Connect 支援執行嵌入突變中的查詢,因此您可以擷取儲存在資料庫中的其他授權條件,並在 @check
指令中使用這些條件,判斷是否授權封閉突變。在這個授權案例中,@redact
指令可讓您控管是否要透過連線通訊協定將查詢結果傳回給用戶端,以及是否要在產生的 SDK 中省略內嵌查詢。請參閱這些指令的簡介和範例。
瞭解 @auth
指令
您可以將 @auth
指令參數化,以遵循涵蓋許多常見存取情境的預設存取層級。這些層級的範圍從 PUBLIC
(允許所有用戶端查詢及變動,不需任何驗證) 到 NO_ACCESS
(禁止在使用 Firebase Admin SDK 的特權伺服器環境以外查詢及變動)。每個層級都與 Firebase Authentication 提供的驗證流程相關。
等級 | 定義 |
---|---|
PUBLIC |
無論是否經過驗證,任何人都能執行這項作業。 |
PUBLIC |
無論是否經過驗證,任何人都能執行這項作業。 |
USER_ANON |
任何已識別的使用者 (包括以匿名方式登入 Firebase Authentication 的使用者) 都有權執行查詢或變動。 |
USER |
登入 Firebase Authentication 的使用者皆可執行查詢或變動,匿名登入使用者除外。 |
USER_EMAIL_VERIFIED |
只要使用者以 Firebase Authentication 登入,並提供經過驗證的電子郵件地址,即可執行查詢或突變。 |
NO_ACCESS |
這項作業無法在 Admin SDK 環境外執行。 |
以這些預設存取層級為起點,您可以使用 where
篩選器和在伺服器上評估的一般運算語言 (CEL) 運算式,在 @auth
指令中定義複雜且穩固的授權檢查。
使用 @auth
指令實作常見的授權情境
預設存取層級是授權的起點。
USER
存取層級是最實用的基本層級,適合做為起點。
完全安全存取權是以 USER
層級為基礎,加上可檢查使用者屬性、資源屬性、角色和其他檢查項目的篩選器和運算式。USER_ANON
和 USER_EMAIL_VERIFIED
層級是 USER
案例的變體。
您可以使用運算式語法,透過代表作業傳遞的驗證資料的 auth
物件評估資料,包括驗證權杖中的標準資料和權杖中的自訂資料。如需 auth
物件中可用的欄位清單,請參閱參考資料部分。
當然,在某些情況下,PUBLIC
是合適的起始存取層級。再次提醒,存取層級一律是起點,如要確保安全無虞,還需要額外的篩選條件和運算式。
本指南現在提供範例,說明如何以 USER
和 PUBLIC
為基礎建構。
激勵人心的例子
以下最佳做法範例是指部落格平台的結構定義,其中某些內容會鎖定在付費方案後方。
這類平台可能會模擬 Users
和 Posts
。
type User @table(key: "uid") {
uid: String!
name: String
birthday: Date
createdAt: Timestamp! @default(expr: "request.time")
}
type Post @table {
author: User!
text: String!
# "one of 'draft', 'public', or 'pro'"
visibility: String! @default(value: "draft")
# "the time at which the post should be considered published. defaults to
# immediately"
publishedAt: Timestamp! @default(expr: "request.time")
createdAt: Timestamp! @def
ault(expr: "request.time")
updatedAt: Timestamp! @default(expr: "request.time")
}
使用者擁有的資源
在下列情況下,Firebase 建議您編寫可測試使用者資源擁有權的篩選器和運算式,例如 Posts
的擁有權。
在下列範例中,系統會使用運算式讀取及比較授權權杖中的資料。一般模式是使用 where: {authorUid:
{eq_expr: "auth.uid"}}
等運算式,比較儲存的 authorUid
與驗證權杖中傳遞的 auth.uid
(使用者 ID)。
建立
這項授權做法首先會將授權權杖中的 auth.uid
新增至每個新的 Post
,做為 authorUid
欄位,以便在後續授權測試中進行比較。
# Create a new post as the current user
mutation CreatePost($text: String!, $visibility: String) @auth(level: USER) {
post_insert(data: {
# set the author's uid to the current user uid
authorUid_expr: "auth.uid"
text: $text
visibility: $visi
bility
})
}
更新
當用戶端嘗試更新 Post
時,您可以根據儲存的 authorUid
測試傳遞的 auth.uid
。
# Update one of the current user's posts
mutation UpdatePost($id: UUID!, $text: String, $visibility: String) @auth(level:USER) {
post_update(
# only update posts whose author is the current user
first: { where: {
id: {eq: $id}
authorUid: {eq_expr: "auth.uid"}
}}
data: {
text: $text
visibility: $visibility
# insert the current server time for updatedAt
updatedAt_expr: "request
.time"
}
)
}
刪除
授權刪除作業時,也使用相同技術。
# Delete one of the current user's posts
mutation DeletePost($id: UUID!) @auth(level: USER) {
post_delete(
# only delete posts whose author is the current user
first: { where: {
id: {eq: $id}
authorUid: {eq_expr: "auth.uid"}
}}
)
}
# Common display information for a post
fragment DisplayPost on Post {
id, text, createdAt, updatedAt
author { uid, name }
}
清單
# List all posts belonging to the current user
query ListMyPosts @auth(level: USER) {
posts(where: {
userUid: {eq_expr: "auth.uid"}
}) {
# See the fragment above
...DisplayPost
# also show visibility since it is user-controlled
visibil
ity
}
}
GET
# Get a post only if it belongs to the current user
query GetMyPost($id: UUID!) @auth(level: USER) {
post(key: {id: $id},
first: {where: {
id: {eq: $id}
authorUid: {eq_expr: "auth.uid"}}
}}, {
# See the fragment above
...DisplayPost
# also show visibility since it is user-controlled
visibil
ity
}
}
篩選資料
Data Connect 的授權系統可讓您編寫複雜的篩選器,並結合預設存取層級 (例如 PUBLIC
),以及使用授權權杖中的資料。
授權系統也允許您只使用運算式,而不需基本存取層級,如下列部分範例所示。
依資源屬性篩選
由於基本安全等級設為 PUBLIC
,因此這裡的授權並非根據驗證權杖。不過,我們可以在資料庫中明確將記錄設為適合公開存取;假設資料庫中有 Post
筆記錄,且 visibility
設為「公開」。
# List all posts marked as 'public' visibility
query ListPublicPosts @auth(level: PUBLIC) {
posts(where: {
# Test that visibility is "public"
visibility: {eq: "public"}
# Only display articles that are already published
publishedAt: {lt_expr: "request.time"}
}) {
# see the fr
agment above
...DisplayPost
}
}
依使用者聲明篩選
假設您已設定自訂使用者聲明,將驗證權杖傳遞至應用程式,以識別「專業版」方案的使用者,並在驗證權杖中標示 auth.token.plan
欄位。運算式可以針對這個欄位進行測試。
# List all public or pro posts, only permitted if user has "pro" plan claim
query ProListPosts @auth(expr: "auth.token.plan == 'pro'") {
posts(where: {
# display both public posts and "pro" posts
visibility: {in: ['public', 'pro']},
# only display articles that are already published
publishedAt: {lt_expr: "request.time"},
}) {
# see the fragment above
...DisplayPost
# show visibility
so pro users can see which posts are pro\
visibility
}
}
依訂單 + 限制篩選
或者,您可能已在 Post
記錄中設定 visibility
,指出這些內容適用於「專業」使用者,但為了預覽或前導資料清單,您進一步限制了傳回的記錄數量。
# Show 2 oldest Pro post as a preview
query ProTeaser @auth(level: USER) {
posts(
where: {
# show only pro posts
visibility: {eq: "pro"}
# that have already been published more than 30 days ago
publishedAt: {lt_time: {now: true, sub: {days: 30}}}
},
# order by publish time
orderBy: [{publishedAt: DESC}],
# only return two posts
limit: 2
) {
# See the fragment above
...DisplayP
ost
}
}
依角色篩選
如果自訂聲明定義了 admin
角色,您可以據此測試及授權作業。
# List all posts unconditionally iff the current user has an admin claim
query AdminListPosts @auth(expr: "auth.token.admin == true") {
posts { ...Displa
yPost }
}
新增 @check
和 @redact
指令,以便查詢授權資料
常見的授權用途包括在資料庫中儲存自訂授權角色 (例如在特殊權限資料表中),並使用這些角色授權變異,以建立、更新或刪除資料。
您可以使用授權資料查詢,根據 userID 查詢角色,並使用 CEL 運算式判斷變動是否已獲授權。舉例來說,您可能想編寫 UpdateMovieTitle
突變,讓授權用戶端更新電影名稱。
在接下來的討論中,假設電影評論應用程式資料庫會在 MoviePermission
表格中儲存授權角色。
# MoviePermission
# Suppose a user has an authorization role with respect to records in the Movie table
type MoviePermission @table(key: ["movie", "user"]) {
movie: Movie! # implies another field: movieId: UUID!
user: User
!
role: String!
}
用於變異
在下列範例實作中,UpdateMovieTitle
突變包含 query
欄位,可從 MoviePermission
擷取資料,並包含下列指令,確保作業安全無虞且穩定可靠:
@transaction
指令,確保所有授權查詢和檢查作業都會完成,或以不可分割的形式失敗。@redact
指令可從回應中省略查詢結果,也就是說,授權檢查會在 Data Connect 伺服器上執行,但敏感資料不會向用戶端公開。一對
@check
指令,用於評估查詢結果的授權邏輯,例如測試特定使用者 ID 是否具有適當角色,可進行修改。
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"}
# Step 1a: Use @check to test if the user has any role associated with the movie
# Here the `this` binding refers the lookup result, i.e. a MoviePermission object or null
# The `this != null` expression could be omitted since rejecting on null is default behavior
) @check(expr: "this != null", message: "You do not have access to this movie") {
# Step 1b: Check if the user has the editor role for the movie
# Next we execute another @check; now `this` refers to the contents of the `role` field
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
})
}
用於查詢
授權資料查詢也可用於根據角色或其他限制條件來限制查詢。
在下列範例中 (同樣使用 MoviePermission
結構),查詢會檢查要求者是否具備適當的「管理員」角色,可查看可編輯電影的使用者。
query GetMovieEditors($movieId: UUID!) @auth(level: PUBLIC) {
moviePermission(key: { movieId: $movieId, userId_expr: "auth.uid" }) @redact {
role @check(expr: "this == 'admin'", message: "You must be an admin to view all editors of a movie.")
}
moviePermissions(where: { movieId: { eq: $movieId }, role: { eq: "editor" } }) {
user {
id
username
}
}
}
授權時應避免的反模式
上一節介紹使用 @auth
指令時應遵循的模式。
此外,請務必瞭解要避免的重要反模式。
避免在查詢和突變引數中傳遞使用者屬性 ID 和授權權杖參數
Firebase Authentication 是強大的工具,可呈現驗證流程,並安全擷取驗證資料,例如註冊的使用者 ID 和儲存在驗證權杖中的多個欄位。
我們不建議在查詢和變動引數中傳遞使用者 ID 和驗證權杖資料。
# Antipattern!
# This incorrectly allows any user to view any other user's posts
query AllMyPosts($userId: String!) @auth(level: USER) {
posts(where: {authorUid: {eq: $userId}}) {
id, text, createdAt
}
}
避免在沒有任何篩選器的情況下使用 USER
存取層級
如本指南多次提及,USER
、USER_ANON
和 USER_EMAIL_VERIFIED
等核心存取層級是授權檢查的基準和起點,可透過篩選器和運算式進行強化。如果使用這些層級,但沒有對應的篩選器或運算式來檢查哪個使用者發出要求,就等同於使用 PUBLIC
層級。
# Antipattern!
# This incorrectly allows any user to view all documents
query ListDocuments @auth(level: USER) {
documents {
id
title
text
}
}
避免在原型設計中使用 PUBLIC
或 USER
存取層級
為加快開發速度,您可能會想將所有作業設為 PUBLIC
存取層級或 USER
存取層級,而不進一步強化授權所有作業,以便快速測試程式碼。
以這種方式完成初步原型設計後,請開始從 NO_ACCESS
切換至實際運作的授權,並使用 PUBLIC
和 USER
層級。不過,請勿在未新增其他邏輯的情況下,將這些函式部署為 PUBLIC
或 USER
,如本指南所示。
# Antipattern!
# This incorrectly allows anyone to delete any post
mutation DeletePost($id: UUID!) @auth(level: PUBLIC) {
post: post_delete(
id: $id,
)
}
避免根據未經驗證的電子郵件地址授權
授予特定網域的使用者存取權,是限制存取權的好方法。 不過,任何人在登入時都可以聲稱擁有某個電子郵件地址。請務必只授予透過 Firebase 驗證的電子郵件地址存取權。
# Antipattern!
# Anyone can claim an email address during sign-in
mutation CreatePost($text: String!, $visibility: String) @auth(expr: "auth.token.email.endsWith('@example.com')") {
post_insert(data: {
# set the author's uid to the current user uid
authorUid_expr: "auth.uid"
text: $text
visibility: $visibility
})
}
另請參閱auth.token.email_verified
mutation CreatePost($text: String!, $visibility: String) @auth(expr: "auth.token.email_veri&&fied auth.token.email.endsWith('@example.com')") {
post_insert(data: {
# set the author's uid to the current user uid
authorUid_expr: "auth.uid"
text: $text
visibility: $visibility
})
}
使用 Firebase CLI 稽核授權
如先前所述,PUBLIC
和 USER
等預設存取層級是強大授權的起點,應搭配額外的篩選條件和以運算式為準的授權檢查使用。請務必審慎評估用途,再決定是否單獨使用。
Data Connect 可在您使用 Firebase CLI 部署至伺服器時,分析連結器程式碼,協助稽核授權策略。firebase deploy
您可以透過這項稽核來檢查程式碼集。
部署連結器時,CLI 會輸出連結器中現有、修改和新作業程式碼的評估結果。
如果是經過修改和新增的作業,當您在新作業中使用特定存取層級,或是修改現有作業以使用這些存取層級時,CLI 會發出警告並提示您確認。
系統一律會針對下列情況顯示警告和提示:
PUBLIC
此外,當您未透過 auth.uid
使用篩選器擴增下列存取層級時,系統會顯示警告和提示:
USER
USER_ANON
USER_EMAIL_VERIFIED
使用 @auth(insecureReason:)
引數隱藏不安全作業警告
在許多情況下,您會發現使用 PUBLIC
和 USER*
存取層級非常合適。
如果連接器包含許多作業,您可能希望安全稽核輸出內容更清楚、更相關,並省略通常會觸發警告的作業,但您知道這些作業具有正確的存取層級。
您可以使用 @auth(insecureReason:)
略過這類作業的警告。例如:
query listItem @auth(level: PUBLIC, insecureReason: "This operation is safe to expose to the public.")
{
items {
id name
}
}
使用 Firebase App Check 進行應用程式認證
驗證和授權是Data Connect安全性的重要環節。驗證和授權搭配應用程式認證,可提供非常強大的安全解決方案。
透過 Firebase App Check 認證,執行您應用程式的裝置會使用應用程式或裝置認證供應商,認證 Data Connect 作業來自正版應用程式,要求來自未遭竄改的正版裝置。這項認證會附加至應用程式向 Data Connect 發出的每個要求。
如要瞭解如何為 Data Connect 啟用 App Check,並在應用程式中加入用戶端 SDK,請參閱 App Check 總覽。
@auth(level)
指令的驗證等級
下表列出所有標準存取層級及其對應的 CEL。驗證等級由廣到窄列出,每個等級都包含符合後續等級的所有使用者。
等級 | 定義 |
---|---|
PUBLIC |
無論是否經過驗證,任何人都能執行這項作業。
注意事項:任何使用者都可以讀取或修改資料。 Firebase 建議針對可公開瀏覽的資料 (例如產品或媒體資訊),採用這個授權層級。請參閱最佳做法範例和替代方案。 等同於 @auth(expr: "true")
@auth 篩選條件和運算式無法與這個存取層級一併使用。這類運算式都會失敗,並產生 400 Bad Request 錯誤。 |
USER_ANON |
任何已識別的使用者 (包括以匿名方式登入 Firebase Authentication 的使用者) 都有權執行查詢或變動。 注意: USER_ANON 是 USER 的超集。
注意事項:請注意,您必須仔細設計此授權層級的查詢和異動。這個層級允許使用者匿名登入 (自動登入僅與使用者裝置相關聯),且不會自行執行其他檢查,例如資料是否屬於使用者。Authentication請參閱最佳做法範例和替代方案。 由於Authentication匿名登入流程會發出 uid ,因此
USER_ANON 層級等同於
@auth(expr: "auth.uid != nil")
|
USER |
登入 Firebase Authentication 的使用者皆可執行查詢或變動,匿名登入使用者除外。 注意事項:請注意,您必須仔細設計此授權層級的查詢和異動。這個層級只會檢查使用者是否已登入 Authentication,不會自行執行其他檢查,例如資料是否屬於使用者。請參閱最佳做法範例和替代方案。 相當於 @auth(expr: "auth.uid != nil &&
auth.token.firebase.sign_in_provider != 'anonymous'")"
|
USER_EMAIL_VERIFIED |
只要使用者以 Firebase Authentication 登入,並提供經過驗證的電子郵件地址,即可執行查詢或突變。
注意事項:由於電子郵件驗證是使用 Authentication 進行,因此是以更強大的 Authentication 方法為基礎,相較於 USER 或 USER_ANON ,這個層級可提供額外安全防護。這個層級只會檢查使用者是否已透過 Authentication 登入,且電子郵件地址已通過驗證,不會自行執行其他檢查,例如檢查資料是否屬於使用者。請參閱最佳做法範例和替代方案。相當於 @auth(expr: "auth.uid != nil &&
auth.token.email_verified")" |
NO_ACCESS |
這項作業無法在 Admin SDK 環境外執行。
相當於 @auth(expr: "false") |
@auth(expr)
的 CEL 參考資料
如本指南其他地方的範例所示,您可以使用一般運算語言 (CEL) 中定義的運算式,透過 @auth(expr:)
和 @check
指令控制 Data Connect 的授權。
本節將說明建立這些指令運算式時適用的 CEL 語法。
如需完整的 CEL 參考資訊,請參閱 CEL 規格。
在查詢和突變中傳遞的測試變數
@auth(expr)
語法可讓您存取及測試查詢和變動中的變數。
舉例來說,您可以使用 vars.status
納入作業變數,例如 $status
。
mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.statu
s)")
運算式可用的資料:要求、回應、this
資料的用途包括:
- 在
@auth(expr:)
和@check(expr:)
指令中,使用 CEL 運算式進行評估 - 使用伺服器運算式指派,
<field>_expr
。
@auth(expr:)
和 @check(expr:)
CEL 運算式都可以評估下列項目:
request.operationName
vars
(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.va
riables.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.todoLis<t_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 != n&&ull) (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 存取該聲明。 |
後續步驟
- Firebase Data Connect 提供 Admin SDK,讓您從具備特殊權限的環境執行查詢和突變。
- 如要瞭解身分與存取權管理安全性,請參閱服務和資料庫管理指南。