Firebase Data Connect มีการรักษาความปลอดภัยฝั่งไคลเอ็นต์ที่มีประสิทธิภาพด้วยสิ่งต่อไปนี้
- การให้สิทธิ์ไคลเอ็นต์บนอุปกรณ์เคลื่อนที่และเว็บ
- การควบคุมการให้สิทธิ์ระดับการค้นหาและระดับการดัดแปลงแต่ละรายการ
- การรับรองแอปด้วย Firebase App Check
Data Connect ขยายความปลอดภัยนี้ด้วยสิ่งต่อไปนี้
- การให้สิทธิ์ฝั่งเซิร์ฟเวอร์
- ความปลอดภัยของผู้ใช้โปรเจ็กต์ Firebase และ Cloud SQL ด้วย IAM
ให้สิทธิ์การค้นหาและการดัดแปลงไคลเอ็นต์
Data Connect ผสานรวมกับ Firebase Authentication อย่างเต็มรูปแบบ คุณจึงใช้ข้อมูลที่เป็นริชมีเดียเกี่ยวกับผู้ใช้ที่เข้าถึงข้อมูลของคุณ (การตรวจสอบสิทธิ์) ในการออกแบบเพื่อกำหนดข้อมูลที่จะให้ผู้ใช้เหล่านั้นเข้าถึงได้ (การให้สิทธิ์)
Data Connect มีคำสั่ง @auth
สําหรับการค้นหาและการดัดแปลง ซึ่งช่วยให้คุณกําหนดระดับการตรวจสอบสิทธิ์ที่จําเป็นในการให้สิทธิ์การดําเนินการได้ คู่มือนี้จะแนะนำคำสั่ง @auth
พร้อมตัวอย่าง
นอกจากนี้ Data Connect ยังรองรับการดำเนินการค้นหาที่ฝังอยู่ในมิวเทชัน เพื่อให้คุณเรียกข้อมูลเกณฑ์การให้สิทธิ์เพิ่มเติมที่เก็บไว้ในฐานข้อมูลได้ และใช้เกณฑ์เหล่านั้นในคำสั่ง @check
เพื่อตัดสินใจว่ามิวเทชันที่รวมอยู่นั้นได้รับอนุญาตหรือไม่ ในกรณีการให้สิทธิ์นี้ คำสั่ง @redact
ช่วยให้คุณควบคุมได้ว่าจะให้ระบบแสดงผลลัพธ์การค้นหาแก่ไคลเอ็นต์ใน Wire Protocol และละเว้นการค้นหาที่ฝังไว้ใน 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 ช่วยให้คุณเขียนตัวกรองที่ซับซ้อนซึ่งรวมกับระดับการเข้าถึงที่กำหนดไว้ล่วงหน้า เช่น 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 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
เพื่อระบุว่าเป็นเนื้อหาที่พร้อมให้บริการสำหรับผู้ใช้ "Pro" แต่สำหรับข้อมูลตัวอย่างหรือข้อมูลพรีวิว ให้จำกัดจำนวนระเบียนที่แสดงผลเพิ่มเติม
# 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
คำสั่ง @check
จะยืนยันว่าช่องที่ระบุมีอยู่ในผลการค้นหา นิพจน์ Common Expression Language (CEL) ใช้เพื่อทดสอบค่าฟิลด์ ลักษณะการทํางานเริ่มต้นของคําสั่งคือตรวจสอบและปฏิเสธโหนดที่มีค่า null
คำสั่ง @redact
จะปกปิดข้อมูลบางส่วนในการตอบกลับจากไคลเอ็นต์ ระบบจะยังคงประเมินช่องที่ถูกปกปิดเพื่อหาผลข้างเคียง (รวมถึงการเปลี่ยนแปลงข้อมูลและ @check
) และผลลัพธ์จะยังคงใช้ได้กับขั้นตอนต่อๆ ไปในนิพจน์ CEL
ใน Data Connect คำสั่ง @check
และ @redact
มักใช้ในบริบทของการตรวจสอบการให้สิทธิ์ โปรดดูการอภิปรายเกี่ยวกับการค้นหาข้อมูลการให้สิทธิ์
เพิ่มคําแนะนํา @check
และ @redact
เพื่อค้นหาข้อมูลการให้สิทธิ์
Use Case การให้สิทธิ์ที่พบบ่อยเกี่ยวข้องกับการจัดเก็บบทบาทการให้สิทธิ์ที่กําหนดเองในฐานข้อมูล เช่น ในตารางสิทธิ์พิเศษ และใช้บทบาทเหล่านั้นเพื่ออนุญาตให้ทําการเปลี่ยนแปลงเพื่อสร้าง อัปเดต หรือลบข้อมูล
เมื่อใช้การค้นหาข้อมูลการให้สิทธิ์ คุณจะค้นหาบทบาทตามรหัสผู้ใช้ได้และใช้นิพจน์ CEL เพื่อตัดสินใจว่ามีการอนุญาตให้ทำการเปลี่ยนแปลงหรือไม่ เช่น คุณอาจต้องเขียน UpdateMovieTitle
mutation ที่อนุญาตให้ไคลเอ็นต์ที่ได้รับอนุญาตอัปเดตชื่อภาพยนตร์
ในส่วนที่เหลือของการสนทนานี้ เราจะสมมติว่าฐานข้อมูลแอปรีวิวภาพยนตร์จัดเก็บบทบาทการให้สิทธิ์ไว้ในตาราง MoviePermission
# MoviePermission
# Suppose a user has an authorization role with respect to records in the Movie table
type MoviePermission @table(key: ["doc", "userId"]) {
movie: Movie! # implies another field: movieId: UUID!
userId: String! # Can also be a reference to a User table, doesn't matter
role: String!
}
ในตัวอย่างการใช้งานต่อไปนี้ UpdateMovieTitle
mutation มีฟิลด์ query
เพื่อดึงข้อมูลจาก MoviePermission
และคำสั่งต่อไปนี้เพื่อให้การดำเนินการปลอดภัยและมีประสิทธิภาพ
- คำสั่ง
@transaction
เพื่อให้การค้นหาและการตรวจสอบการให้สิทธิ์ทั้งหมดเสร็จสมบูรณ์หรือดำเนินการไม่สำเร็จพร้อมกัน - คำสั่ง
@redact
เพื่อละเว้นผลการค้นหาจากการตอบกลับ ซึ่งหมายความว่าการตรวจสอบการให้สิทธิ์จะดำเนินการในเซิร์ฟเวอร์ Data Connect แต่จะไม่แสดงข้อมูลที่ละเอียดอ่อนต่อไคลเอ็นต์ คำสั่ง
@check
2 รายการเพื่อประเมินตรรกะการให้สิทธิ์ในผลการค้นหา เช่น การทดสอบว่ารหัสผู้ใช้หนึ่งๆ มีบทบาทที่เหมาะสมในการทําการแก้ไข
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
})
}
รูปแบบที่ไม่พึงประสงค์ที่ควรหลีกเลี่ยงในการให้สิทธิ์
ส่วนก่อนหน้านี้กล่าวถึงรูปแบบที่ควรทำตามเมื่อใช้คำสั่ง @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 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)
และ @check(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)")
ข้อมูลที่แสดงในนิพจน์
ทั้งนิพจน์ CEL @auth(expr:)
และ @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
ในตัวกรองและนิพจน์
ออบเจ็กต์ 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
เท่านั้น แต่จะไม่มีการประเมินเมื่อ this
เป็น 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 อาจเป็นบูลีน int ลอย ตัวเลข สตริง รายการ แผนที่ การประทับเวลา หรือระยะเวลา |
ซ้ายไปขวา |
a==b a!=b |
โอเปอเรเตอร์การเปรียบเทียบ | ซ้ายไปขวา |
a && b |
AND แบบมีเงื่อนไข | ซ้ายไปขวา |
a || b |
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 |
tenantId ที่เชื่อมโยงกับบัญชี หากมี เช่น 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 ในคู่มือการจัดการบริการและฐานข้อมูล