Firebase Data Connect ให้การรักษาความปลอดภัยฝั่งไคลเอ็นต์ที่แข็งแกร่งด้วยสิ่งต่อไปนี้
- การให้สิทธิ์ไคลเอ็นต์บนอุปกรณ์เคลื่อนที่และเว็บ
 - การควบคุมการให้สิทธิ์ระดับการค้นหาและการเปลี่ยนแปลงแต่ละรายการ
 - การรับรองแอปด้วย Firebase App Check
 
Data Connect ขยายการรักษาความปลอดภัยนี้ด้วย
- การให้สิทธิ์ฝั่งเซิร์ฟเวอร์
 - ความปลอดภัยของโปรเจ็กต์ Firebase และผู้ใช้ Cloud SQL ด้วย IAM
 
ให้สิทธิ์การค้นหาและการเปลี่ยนแปลงของไคลเอ็นต์
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 ไม่ได้ | 
คุณสามารถใช้ระดับการเข้าถึงที่กำหนดไว้ล่วงหน้าเหล่านี้เป็นจุดเริ่มต้นเพื่อกำหนดการตรวจสอบการให้สิทธิ์ที่ซับซ้อนและมีประสิทธิภาพในคำสั่ง @auth โดยใช้ตัวกรอง where และนิพจน์ Common Expression Language (CEL) ที่ประเมินในเซิร์ฟเวอร์
ใช้คำสั่ง @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! @default(expr: "request.time")
  updatedAt: Timestamp! @default(expr: "request.time")
}
ทรัพยากรที่ผู้ใช้เป็นเจ้าของ
Firebase ขอแนะนําให้คุณเขียนตัวกรองและนิพจน์ที่ทดสอบความเป็นเจ้าของทรัพยากรของผู้ใช้ในกรณีต่อไปนี้ ความเป็นเจ้าของ Posts
ในตัวอย่างต่อไปนี้ ระบบจะอ่านและเปรียบเทียบข้อมูลจากโทเค็นการให้สิทธิ์โดยใช้
นิพจน์ รูปแบบทั่วไปคือการใช้นิพจน์ เช่น where: {authorUid:
{eq_expr: "auth.uid"}} เพื่อเปรียบเทียบ authorUid ที่จัดเก็บไว้กับ auth.uid
(รหัสผู้ใช้) ที่ส่งในโทเค็นการตรวจสอบสิทธิ์
สร้าง
แนวทางปฏิบัติด้านการให้สิทธิ์นี้เริ่มต้นด้วยการเพิ่ม 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: $visibility
  })
}
อัปเดต
เมื่อไคลเอ็นต์พยายามอัปเดต Post คุณจะทดสอบ auth.uid ที่ส่งผ่าน
กับ authorUid ที่จัดเก็บไว้ได้
# 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
    visibility
  }
}
ดาวน์โหลด
# 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
      visibility
  }
}
กรองข้อมูล
Data Connect's authorization system lets you write sophisticated
filters combined with preset access levels like PUBLIC as well as by using
data from auth tokens.
ระบบการให้สิทธิ์ยังช่วยให้คุณใช้เฉพาะนิพจน์ได้โดยไม่ต้องมี ระดับการเข้าถึงพื้นฐาน ดังที่แสดงในตัวอย่างบางส่วนต่อไปนี้
กรองตามแอตทริบิวต์ของทรัพยากร
ในที่นี้ การให้สิทธิ์ไม่ได้อิงตามโทเค็นการตรวจสอบสิทธิ์เนื่องจากมีการตั้งค่าระดับความปลอดภัยพื้นฐานเป็น 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 fragment above
    ...DisplayPost
  }
}
กรองตามการอ้างสิทธิ์ของผู้ใช้
ในที่นี้ สมมติว่าคุณได้ตั้งค่าการอ้างสิทธิ์ของผู้ใช้ที่กำหนดเองซึ่งส่งในโทเค็นการตรวจสอบสิทธิ์เพื่อระบุผู้ใช้ในแพ็กเกจ "Pro" สำหรับแอปของคุณ โดยมีการติดแฟล็กด้วย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
  }
}
กรองตามคำสั่ง + ขีดจำกัด
หรือคุณอาจตั้งค่า visibility ในระเบียน Post เพื่อระบุว่าระเบียนเหล่านั้นเป็นเนื้อหาที่พร้อมให้บริการสำหรับผู้ใช้ "มืออาชีพ" แต่สำหรับการแสดงตัวอย่างหรือการแสดงข้อมูลทีเซอร์ ให้จำกัดจำนวนระเบียนที่แสดงเพิ่มเติม
# 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
    ...DisplayPost
  }
}
กรองตามบทบาท
หากการอ้างสิทธิ์ที่กำหนดเองของคุณกำหนดadminบทบาท คุณจะทดสอบและให้สิทธิ์
การดำเนินการได้ตามนั้น
# List all posts unconditionally iff the current user has an admin claim
query AdminListPosts @auth(expr: "auth.token.admin == true") {
  posts { ...DisplayPost }
}
เพิ่มคำสั่ง @check และ @redact เพื่อค้นหาข้อมูลการให้สิทธิ์
Use Case การให้สิทธิ์ที่พบบ่อยเกี่ยวข้องกับการจัดเก็บบทบาทการให้สิทธิ์ที่กำหนดเองใน ฐานข้อมูลของคุณ เช่น ในตารางสิทธิ์พิเศษ และการใช้บทบาทเหล่านั้น เพื่อให้สิทธิ์การเปลี่ยนแปลงในการสร้าง อัปเดต หรือลบข้อมูล
การใช้การค้นหาข้อมูลการให้สิทธิ์ช่วยให้คุณค้นหาบทบาทตามรหัสผู้ใช้และ
ใช้นิพจน์ CEL เพื่อตัดสินว่าการเปลี่ยนแปลงได้รับอนุญาตหรือไม่ ตัวอย่างเช่น คุณอาจต้องการเขียน UpdateMovieTitleMutation ที่อนุญาตให้ไคลเอ็นต์ที่ได้รับอนุญาต
อัปเดตชื่อภาพยนตร์
สำหรับการอภิปรายที่เหลือนี้ ให้ถือว่าฐานข้อมูลแอปรีวิวภาพยนตร์จัดเก็บ
บทบาทการให้สิทธิ์ใน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คำสั่งเพื่อประเมินตรรกะการให้สิทธิ์ในผลการค้นหา เช่น การทดสอบว่า userID ที่ระบุมีบทบาทที่เหมาะสมในการทำการแก้ไข หรือไม่
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
นอกจากนี้ คุณควรทราบถึงรูปแบบที่ไม่ควรทำที่สำคัญเพื่อหลีกเลี่ยงด้วย
หลีกเลี่ยงการส่งรหัสแอตทริบิวต์ผู้ใช้และพารามิเตอร์โทเค็นการให้สิทธิ์ในอาร์กิวเมนต์การค้นหาและการเปลี่ยนแปลง
Firebase Authentication เป็นเครื่องมือที่มีประสิทธิภาพในการนำเสนอโฟลว์การตรวจสอบสิทธิ์และ บันทึกข้อมูลการตรวจสอบสิทธิ์อย่างปลอดภัย เช่น รหัสผู้ใช้ที่ลงทะเบียนและฟิลด์จำนวนมาก ที่จัดเก็บไว้ในโทเค็นการตรวจสอบสิทธิ์
ไม่แนะนําให้ส่งรหัสผู้ใช้และข้อมูลโทเค็นการให้สิทธิ์ในอาร์กิวเมนต์การค้นหาและการเปลี่ยนแปลง
# 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_verified && 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 เป็นจุดเริ่มต้นสำหรับการให้สิทธิ์ที่แข็งแกร่ง และ
ควรใช้ร่วมกับการตรวจสอบการให้สิทธิ์เพิ่มเติมตามตัวกรองและนิพจน์
ไม่ควรใช้โดยลำพังโดยไม่พิจารณา Use Case อย่างรอบคอบ
Data Connect ช่วยให้คุณตรวจสอบกลยุทธ์การให้สิทธิ์ได้โดยการวิเคราะห์โค้ดตัวเชื่อมต่อเมื่อคุณ
ติดตั้งใช้งานในเซิร์ฟเวอร์โดยใช้ firebase deploy จาก Firebase CLI คุณใช้การตรวจสอบนี้เพื่อช่วยตรวจสอบโค้ดเบสได้
เมื่อคุณติดตั้งใช้งานตัวเชื่อมต่อ CLI จะแสดงผลการประเมินสำหรับโค้ดการดำเนินการที่มีอยู่ ที่แก้ไขแล้วและโค้ดการดำเนินการใหม่ในตัวเชื่อมต่อ
สำหรับการดำเนินการที่แก้ไขและใหม่ CLI จะแสดงคำเตือนและแจ้งให้คุณยืนยันเมื่อใช้ระดับการเข้าถึงบางอย่างในการดำเนินการใหม่ หรือเมื่อแก้ไขการดำเนินการที่มีอยู่เพื่อใช้ระดับการเข้าถึงเหล่านั้น
คำเตือนและข้อความแจ้งจะเกิดขึ้นเสมอในกรณีต่อไปนี้
PUBLIC
และคำเตือนและข้อความแจ้งจะปรากฏในระดับการเข้าถึงต่อไปนี้เมื่อคุณไม่ได้เพิ่มด้วยตัวกรองโดยใช้ auth.uid
USERUSER_ANONUSER_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
หากต้องการดูวิธีเปิดใช้ App Check สำหรับ Data Connect และรวม 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") | 
    
ข้อมูลอ้างอิง CEL สำหรับ @auth(expr)
ดังที่แสดงในตัวอย่างที่อื่นในคู่มือนี้ คุณสามารถและควรใช้นิพจน์ที่กำหนดไว้ใน Common Expression Language (CEL) เพื่อควบคุมการให้สิทธิ์สำหรับ Data Connect โดยใช้คำสั่ง @auth(expr:) และ @check
ส่วนนี้ครอบคลุมไวยากรณ์ CEL ที่เกี่ยวข้องกับการสร้างนิพจน์สำหรับ คำสั่งเหล่านี้
ดูข้อมูลอ้างอิงทั้งหมดสำหรับ CEL ได้ใน ข้อกำหนด CEL
ส่งตัวแปรทดสอบในคําค้นหาและการเปลี่ยนแปลง
@auth(expr) ไวยากรณ์ช่วยให้คุณเข้าถึงและทดสอบตัวแปรจากคําค้นหาและการเปลี่ยนแปลงได้
เช่น คุณสามารถรวมตัวแปรการดำเนินการ เช่น $status โดยใช้
vars.status
mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")
ข้อมูลที่ใช้ได้กับนิพจน์: request, response, this
คุณใช้ข้อมูลเพื่อ
- การประเมินด้วยนิพจน์ CEL ในคำสั่ง 
@auth(expr:)และ@check(expr:) - การกำหนดค่าโดยใช้นิพจน์เซิร์ฟเวอร์ 
<field>_expr 
ทั้งนิพจน์ CEL @auth(expr:) และ @check(expr:) สามารถประเมินรายการต่อไปนี้ได้
request.operationNamevars(ชื่อแทนสำหรับrequest.variables)auth(ชื่อแทนสำหรับrequest.auth)
ในการเปลี่ยนแปลง คุณสามารถเข้าถึงและกำหนดเนื้อหาของรายการต่อไปนี้ได้
response(เพื่อตรวจสอบผลลัพธ์บางส่วนในตรรกะแบบหลายขั้นตอน)
นอกจากนี้ นิพจน์ @check(expr:) ยังประเมินค่าต่อไปนี้ได้ด้วย
this(ค่าของฟิลด์ปัจจุบัน)response(เพื่อตรวจสอบผลลัพธ์บางส่วนในตรรกะแบบหลายขั้นตอน)
การเชื่อมโยง request.operationName
request.operarationName binding stores the type of operation, either query
or mutation.
การเชื่อมโยง 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: รหัสผู้ใช้ที่ไม่ซ้ำกันซึ่งกำหนดให้กับผู้ใช้ที่ขอtoken: แผนที่ของค่าที่รวบรวมโดย Authentication
ดูรายละเอียดเพิ่มเติมเกี่ยวกับเนื้อหาของ auth.token ได้ที่
ข้อมูลในโทเค็นการให้สิทธิ์
การเชื่อมโยง response
response Binding มีข้อมูลที่เซิร์ฟเวอร์รวบรวมเพื่อตอบกลับการค้นหาหรือการเปลี่ยนแปลงขณะที่รวบรวมข้อมูลนั้น
เมื่อการดำเนินการดำเนินไปและแต่ละขั้นตอนเสร็จสมบูรณ์แล้ว
response จะมีข้อมูลการตอบกลับจากขั้นตอนที่เสร็จสมบูรณ์แล้ว
responseการเชื่อมโยงมีโครงสร้างตามรูปร่างของ
การดำเนินการที่เชื่อมโยง รวมถึงฟิลด์แบบซ้อน (หลายรายการ) และคิวรีที่ฝัง (หากมี)
โปรดทราบว่าเมื่อเข้าถึงข้อมูลการตอบกลับการค้นหาที่ฝัง ฟิลด์อาจมี
ข้อมูลประเภทใดก็ได้ ทั้งนี้ขึ้นอยู่กับข้อมูลที่ขอในการค้นหาที่ฝัง เมื่อคุณ
เข้าถึงข้อมูลที่ฟิลด์การเปลี่ยนแปลง เช่น _insert และ _delete แสดงผล ฟิลด์ดังกล่าวอาจ
มีคีย์ UUID, จำนวนการลบ, ค่า Null (ดูข้อมูลอ้างอิงการเปลี่ยนแปลง)
เช่น
- ในการเปลี่ยนแปลงที่มีการฝังการค้นหา 
responseการเชื่อมโยงจะมีข้อมูลการค้นหาที่response.query.<fieldName>.<fieldName>....ใน กรณีนี้คือresponse.query.todoListและresponse.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
    }
  }
}
- ในการเปลี่ยนแปลงหลายขั้นตอน เช่น มีฟิลด์ 
_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,
        number, string, list, map, timestamp หรือ duration | 
      ซ้ายไปขวา | 
a==b a!=b | 
      โอเปอเรเตอร์การเปรียบเทียบ | ซ้ายไปขวา | 
a && b | 
      AND แบบมีเงื่อนไข | ซ้ายไปขวา | 
a || b | 
      Conditional OR | ซ้ายไปขวา | 
a ? true_value : false_value | 
      นิพจน์ Ternary | ซ้ายไปขวา | 
ข้อมูลในโทเค็นการตรวจสอบสิทธิ์
auth.token ออบเจ็กต์อาจมีค่าต่อไปนี้
| ช่อง | คำอธิบาย | 
|---|---|
email | 
อีเมลที่เชื่อมโยงกับบัญชี (หากมี) | 
email_verified | 
true หากผู้ใช้ยืนยันว่าตนมีสิทธิ์เข้าถึงอีเมล email ผู้ให้บริการบางรายจะยืนยันอีเมลของตนโดยอัตโนมัติ | 
phone_number | 
หมายเลขโทรศัพท์ที่เชื่อมโยงกับบัญชี (หากมี) | 
name | 
ชื่อที่แสดงของผู้ใช้ หากตั้งค่าไว้ | 
sub | 
UID ของ 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 | 
    เวลาที่ออก | เวลาปัจจุบันเป็นวินาทีนับตั้งแต่ Epoch ของ UNIX | 
exp | 
    เวลาหมดอายุ | 
      เวลาเป็นวินาทีนับตั้งแต่ Epoch ของ UNIX ที่โทเค็นหมดอายุ โดยช้ากว่าiat ได้สูงสุด 3,600 วินาที
      หมายเหตุ: การตั้งค่านี้จะควบคุมเฉพาะเวลาที่โทเค็นที่กำหนดเองหมดอายุ เท่านั้น แต่เมื่อคุณให้ผู้ใช้ลงชื่อเข้าใช้โดยใช้ signInWithCustomToken() ผู้ใช้จะยังคงลงชื่อเข้าใช้อุปกรณ์
      จนกว่าเซสชันจะใช้งานไม่ได้หรือผู้ใช้จะออกจากระบบ
     | 
  
<claims> (ไม่บังคับ) | 
    
      การอ้างสิทธิ์ที่กำหนดเองที่ไม่บังคับเพื่อรวมไว้ในโทเค็น ซึ่งเข้าถึงได้ผ่าน
      auth.token (หรือ request.auth.token) ใน
      นิพจน์ เช่น หากสร้างการอ้างสิทธิ์ที่กำหนดเอง
      adminClaim คุณจะเข้าถึงการอ้างสิทธิ์ดังกล่าวได้ด้วย
      auth.token.adminClaim
     | 
  |
ขั้นตอนต่อไปคืออะไร
- Firebase Data Connect มี Admin SDK เพื่อให้คุณทำ การค้นหาและการเปลี่ยนแปลงจากสภาพแวดล้อมที่มีสิทธิ์
 - ดูข้อมูลเกี่ยวกับการรักษาความปลอดภัยของ IAM ในคู่มือการจัดการบริการและฐานข้อมูล