מסמך עזר בנושא תחביר של Common Expression Language ל-Data Connect

במדריכים האלה מוסבר על תחביר של Common Expression Language ‏ (CEL) שרלוונטי ליצירת ביטויים להנחיות @auth(expr:) ו-@check(expr:).

מידע מפורט על CEL זמין במפרט של CEL.

בדיקת משתנים שמועברים בשאילתות ובמוטציות

התחביר של @auth(expr) מאפשר לגשת למשתנים משאילתות וממוטציות ולבדוק אותם.

לדוגמה, אפשר לכלול משתנה פעולה, כמו $status, באמצעות vars.status.

mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")

נתונים שזמינים לביטויים

גם ביטוי ה-CEL @auth(expr:) וגם ביטוי ה-CEL @check(expr:) יכולים להעריך את האפשרויות הבאות:

  • request.operationName
  • vars (כתובת אימייל חלופית ל-request.variables)
  • auth (כתובת אימייל חלופית ל-request.auth)

בנוסף, ביטויים של @check(expr:) יכולים להעריך:

  • this (הערך של השדה הנוכחי)

האובייקט request.operationName

באובייקט request.operarationName מאוחסן סוג הפעולה, שאילתה או מוטציה.

האובייקט 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

Authentication מזהה משתמשים שמבקשים גישה לנתונים שלכם ומספק את המידע הזה כאובייקט שאפשר להשתמש בו בביטויים שלכם.

במסננים ובביטויים, אפשר להשתמש ב-auth ככינוי ל-request.auth.

אובייקט האימות מכיל את הפרטים הבאים:

  • uid: מזהה משתמש ייחודי שהוקצה למשתמש מבצע הבקשה.
  • token: מפה של ערכים שנאספו על ידי Authentication.

מידע נוסף על התוכן של auth.token זמין במאמר נתונים באסימוני אימות.

הקישור 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 או מותנה משמאל לימין
a ? true_value : false_value ביטוי טרינרי משמאל לימין

נתונים בטוקני אימות

האובייקט auth.token יכול להכיל את הערכים הבאים:

שדה תיאור
email כתובת האימייל שמשויכת לחשבון, אם יש כזו.
email_verified true אם המשתמש אימת שיש לו גישה לכתובת email. ספקים מסוימים מאמתים באופן אוטומטי כתובות אימייל שבבעלותם.
phone_number מספר הטלפון שמשויך לחשבון, אם קיים.
name השם המוצג של המשתמש, אם הוא מוגדר.
sub מזהה המשתמש ב-Firebase. השם הזה ייחודי בפרויקט.
firebase.identities מילון של כל הזהויות שמשויכות לחשבון של המשתמש הזה. המפתחות של המילון יכולים להיות כל אחד מהערכים הבאים: email, phone, google.com, facebook.com, github.com, twitter.com. הערכים במילון הם מערכי מזהים ייחודיים לכל ספק זהויות שמשויך לחשבון. לדוגמה, השדה auth.token.firebase.identities["google.com"][0] מכיל את מזהה המשתמש הראשון ב-Google שמשויך לחשבון.
firebase.sign_in_provider ספק הכניסה לחשבון ששימש לקבלת האסימון הזה. יכול להיות אחת מהמחרוזות הבאות: custom, ‏ password, ‏ phone, ‏ anonymous, ‏ google.com, ‏ facebook.com, ‏ github.com, ‏ twitter.com.
firebase.tenant מזהה הדייר שמשויך לחשבון, אם הוא קיים. לדוגמה, tenant2-m6tyz

שדות נוספים באסימונים מזהים מסוג JWT

אפשר גם לגשת לשדות auth.token הבאים:

הצהרות מותאמות אישית על אסימונים
alg אלגוריתם "RS256"
iss המנפיק כתובת האימייל של חשבון השירות של הפרויקט
sub נושא כתובת האימייל של חשבון השירות של הפרויקט
aud קהל "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat שעת ההנפקה השעה הנוכחית, בשניות מאז ראשית זמן יוניקס (Unix epoch)
exp מועד תפוגה הזמן, בשניות מאז ראשית זמן יוניקס (Unix epoch), שבו יפוג תוקף האסימון. הוא יכול להיות עד 3,600 שניות מאוחר יותר מ-iat.
הערה: ההגדרה הזו קובעת רק את הזמן שבו יפוג התוקף של האסימון בהתאמה אישית עצמו. עם זאת, אחרי שמשתמש מתחבר באמצעות signInWithCustomToken(), הוא נשאר מחובר למכשיר עד שהסשן שלו יבוטל או עד שהוא יתנתק.
ֶ<claims> (אופציונלי) הצהרות אופציונליות בהתאמה אישית שאפשר לכלול באסימון, וניתן לגשת אליהן באמצעות auth.token (או request.auth.token) בביטויים. לדוגמה, אם יוצרים תלונה מותאמת אישית adminClaim, אפשר לגשת אליה באמצעות auth.token.adminClaim.