توفّر Firebase Data Connect أمانًا قويًا من جهة العميل من خلال:
- تفويض برنامج الويب والتطبيق المتوافق مع الأجهزة الجوّالة
- عناصر التحكّم في الإذن على مستوى الاستعلامات الفردية وعمليات التحويل
- شهادة اعتماد التطبيق من Firebase App Check
توفّر Data Connect ميزات أمان إضافية، مثل:
- التفويض من جهة الخادم
- أمان مستخدمي مشروع Firebase وCloud SQL باستخدام "إدارة الهوية وإمكانية الوصول"
تفويض طلبات بحث العميل وتعديلاته
إنّ Data Connect مدمجة بالكامل مع Firebase Authentication، لذا يمكنك استخدام بيانات غنية عن المستخدمين الذين يصلون إلى بياناتك (المصادقة) في تصميمك للبيانات التي يمكن لهؤلاء المستخدمين الوصول إليها (التفويض).
يوفّر Data Connect توجيه @auth
لطلبات البحث وعمليات
التحويل التي تتيح لك ضبط مستوى المصادقة المطلوب لتفويض
العملية. يقدّم هذا الدليل
توجيه @auth
مع أمثلة.
بالإضافة إلى ذلك، تتيح Data Connect تنفيذ طلبات البحث المضمّنة في
عمليات التحويل، حتى تتمكّن من استرداد معايير التفويض الإضافية التي تم تخزينها
في قاعدة بياناتك، واستخدام هذه المعايير في توجيهات @check
لتحديد ما إذا كانت
عمليات التحويل المضمّنة مسموحًا بها. في حالة التفويض هذه، تتيح لك التوجيه @redact
التحكّم في ما إذا كانت نتائج طلبات البحث ستتم إعادتها إلى العملاء في
بروتوكول الشبكة وسيتم حذف طلب البحث المضمّن في حِزم SDK التي تم إنشاؤها. يمكنك العثور على
مقدمة عن هذه التعليمات، مع أمثلة.
فهم توجيه @auth
يمكنك تحديد مَعلمات للتوجيه @auth
لاتّباع أحد مستويات الوصول المُعدّة مسبقًا لعدة مرات والتي تغطي العديد من سيناريوهات الوصول الشائعة. تتراوح هذه المستويات بين
PUBLIC
(الذي يسمح بطلبات البحث وعمليات التحويل من جميع العملاء بدون
مصادقة من أي نوع) وNO_ACCESS
(الذي لا يسمح بطلبات البحث و
عمليات التحويل خارج بيئات الخوادم المميّزة باستخدام "حزمة تطوير البرامج (SDK) للمشرف" في Firebase). يرتبط كل مستوى من هذه المستويات بعمليات مصادقة
يوفّرها Firebase Authentication.
المستوى | التعريف |
---|---|
PUBLIC |
يمكن لأي مستخدم تنفيذ العملية مع المصادقة أو بدونها. |
PUBLIC |
يمكن لأي مستخدم تنفيذ العملية مع المصادقة أو بدونها. |
USER_ANON |
أي مستخدم محدّد الهوية، بما في ذلك المستخدمين الذين سجّلوا الدخول بدون الكشف عن هويتهم باستخدام Firebase Authentication، يكون لديه الإذن بتنفيذ طلب البحث أو عملية التحويل. |
USER |
أي مستخدم سجّل الدخول باستخدام Firebase Authentication يكون مفوَّضًا للقيام بعملية البحث أو التحويل باستثناء مستخدمي تسجيل الدخول المجهول الهوية. |
USER_EMAIL_VERIFIED |
إنّ أي مستخدم سجّل الدخول باستخدام Firebase Authentication باستخدام عنوان بريد إلكتروني تم إثبات ملكيته يكون لديه الإذن بتنفيذ طلب البحث أو عملية التحويل. |
NO_ACCESS |
لا يمكن تنفيذ هذه العملية خارج سياق حزمة SDK للمشرف. |
باستخدام مستويات الوصول المُعدّة مسبقًا هذه كنقطة بداية، يمكنك تحديد عمليات تحقّق معقدة و
فعّالة من الأذونات في توجيه @auth
باستخدام فلاتر where
و
تعبيرات لغة التعبير الشائعة (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
سجلّ لتحديد أنّه
محتوى متاح للمستخدمين "المميّزين"، ولكن في حال عرض معاينة أو قائمة دعائية للبيانات،
يمكنك تقييد عدد السجلات التي يتم عرضها بشكل أكبر.
# 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
من توفّر حقول محدّدة في نتائج
الطلب. يتم استخدام تعبير لغة التعبير الشائعة (CEL) لاختبار قيم الحقل. السلوك التلقائي للتوجيه هو البحث عن العقد التي تحتوي على قيمة
null
ورفضها.
يُخفي التوجيه @redact
جزءًا من الاستجابة الواردة من العميل. لا يزال يتم تقييم الحقول التي تم إخفاؤها
بحثًا عن الآثار الجانبية (بما في ذلك تغييرات البيانات و
@check
)، ولا تزال النتائج متاحة للخطوات اللاحقة في تعبيرات CEL.
في Data Connect، غالبًا ما يتم استخدام التوجيهَين @check
و@redact
في سياق عمليات التحقّق من الأذونات. يُرجى الرجوع إلى المناقشة حول البحث في بيانات التفويض.
أضِف التوجيهَين @check
و@redact
للبحث عن بيانات التفويض.
تتضمن حالة الاستخدام الشائعة للسماح بتخزين أدوار التفويض المخصّصة في قاعدة بياناتك، على سبيل المثال في جدول أذونات خاصة، واستخدام تلك الأدوار لتفويض عمليات التحويل لإنشاء البيانات أو تعديلها أو حذفها.
باستخدام عمليات البحث في بيانات التفويض، يمكنك البحث عن الأدوار استنادًا إلى معرّف مستخدم و
استخدام تعبيرات 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
على
حقل query
لاسترداد البيانات من MoviePermission
، بالإضافة إلى
التوجيهات التالية لضمان أمان العملية وفعاليتها:
- توجيه
@transaction
لضمان اكتمال جميع طلبات البحث والتحقّقات المتعلّقة بالتفويض أو تعذّر إكمالها بشكلٍ موحّد - توجيه
@redact
لحذف نتائج طلب البحث من الاستجابة، ما يعني أنّه يتم تنفيذ عملية التحقّق من الإذن على خادم Data Connect ولكن لا يتم عرض البيانات الحسّاسة على العميل. زوج من توجيهات
@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"}
# 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
.
يجب أيضًا أن تكون على دراية بالتصاميم المضادة المهمة التي يجب تجنّبها.
تجنَّب تمرير معرّفات سمات المستخدم ومَعلمات auth token في وسيطات الطلب والتغيير.
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 لعدم صلاحية
الطلب.
|
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 |
لا يمكن تنفيذ هذه العملية خارج سياق حزمة SDK للمشرف.
ما يعادل @auth(expr: "false") |
مرجع CEL للملفَّين @auth(expr)
و@check(expr)
كما هو موضّح في الأمثلة الواردة في أماكن أخرى من هذا الدليل، يمكنك ويجب استخدام
التعبيرات المحدّدة في لغة التعبير الشائعة (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
.
يحتوي عنصر المصادقة على المعلومات التالية:
-
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 منطقيًا أو عددًا صحيحًا أو عددًا برمجيًا أو
سلسلة أو قائمة أو خريطة أو طابعًا زمنيًا أو مدة |
من اليسار إلى اليمين |
a==b a!=b |
عوامل تشغيل المقارنة | من اليسار إلى اليمين |
a && b |
"و" شَرطي | من اليسار إلى اليمين |
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 |
exp |
وقت انتهاء الصلاحية |
الوقت الذي تنتهي فيه صلاحية الرمز المميّز، بالثواني منذ بداية حقبة يونكس يمكن أن يليه
المحتوى بعد 3600 ثانية كحد أقصى من iat .
ملاحظة: لا يتحكّم هذا الإعداد إلا في وقت انتهاء صلاحية الرمز المميّز المخصّص نفسه. ولكن بعد تسجيل دخول مستخدم باستخدام signInWithCustomToken() ، سيظل مسجِّلاً الدخول إلى
الجهاز إلى أن تصبح جلسته غير صالحة أو يسجّل المستخدم الخروج.
|
<claims> (اختياري) |
مطالبات مخصّصة اختيارية لتضمينها في الرمز المميّز، ويمكن الوصول إليها من خلال
auth.token (أو request.auth.token ) في
التعبيرات. على سبيل المثال، إذا أنشأت مطالبة مخصّصة
adminClaim ، يمكنك الوصول إليها باستخدام
auth.token.adminClaim .
|
ما هي الخطوات التالية؟
- يوفّر Firebase Data Connect حزمة SDK للمشرف تتيح لك تنفيذ طلبات البحث والتغييرات من البيئات المميّزة.
- تعرَّف على أمان إدارة الهوية وإمكانية الوصول في دليل إدارة الخدمات وقواعد البيانات.