توفّر 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
(الذي لا يسمح بالاستعلامات والتعديلات خارج بيئات الخادم ذات الامتيازات باستخدام حزمة تطوير البرامج (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! @def
ault(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: $visi
bility
})
}
تعديل
عندما يحاول أحد العملاء تعديل 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
visibil
ity
}
}
جلب
# 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
}
}
الفلترة حسب الترتيب والحدّ
أو قد تكون قد ضبطت 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
...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
للبحث عن بيانات التفويض
تتضمّن إحدى حالات استخدام التفويض الشائعة تخزين أدوار التفويض المخصّصة في قاعدة البيانات، مثلاً في جدول الأذونات الخاصة، واستخدام هذه الأدوار للسماح بتعديلات لإنشاء البيانات أو تعديلها أو حذفها.
باستخدام عمليات البحث عن بيانات التفويض، يمكنك طلب أدوار استنادًا إلى معرّف المستخدم واستخدام تعبيرات 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
لتقييم منطق التفويض بشأن نتائج طلب البحث، مثل اختبار ما إذا كان معرّف المستخدم المحدّد لديه الدور المناسب لإجراء تعديلات.
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 Authentication فقط.
# 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 deploy
من واجهة سطر الأوامر Firebase. يمكنك استخدام عملية التدقيق هذه لمساعدتك في مراجعة قاعدة الرموز البرمجية.
عند نشر الموصلات، ستعرض واجهة سطر الأوامر تقييمات لرموز العمليات الحالية والمعدَّلة والجديدة في الموصل.
بالنسبة إلى العمليات المعدَّلة والجديدة، تصدر واجهة سطر الأوامر تحذيرات وتطلب منك التأكيد عند استخدام مستويات وصول معيّنة في عملياتك الجديدة، أو عند تعديل العمليات الحالية لاستخدام مستويات الوصول هذه.
تظهر التحذيرات والإشعارات دائمًا في الحالات التالية:
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.
للتعرّف على كيفية تفعيل 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 |
لا يمكن تنفيذ هذه العملية خارج سياق حزمة تطوير البرامج (SDK) الخاصة بالمشرف.
تعادل @auth(expr: "false") |
مرجع CEL لـ @auth(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.statu
s)")
البيانات المتاحة للتعبيرات: الطلب والاستجابة و"هذا"
يمكنك استخدام البيانات في ما يلي:
- التقييم باستخدام تعابير CEL في التوجيهَين
@auth(expr:)
و@check(expr:)
- تعيين باستخدام تعبيرات الخادم،
<field>_expr
يمكن لكلّ من تعبيرَي CEL @auth(expr:)
و@check(expr:)
تقييم ما يلي:
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
: معرّف مستخدم فريد، يتمّ تعيينه للمستخدم الذي يقدّم الطلب. 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 قيمة منطقية أو عددًا صحيحًا أو عددًا عشريًا أو رقمًا أو سلسلة أو قائمة أو خريطة أو طابعًا زمنيًا أو مدة |
من اليسار إلى اليمين |
a==b a!=b |
عوامل تشغيل المقارنة | من اليسار إلى اليمين |
a && b |
Conditional AND | من اليسار إلى اليمين |
a || b |
Conditional OR | من اليسار إلى اليمين |
a ? true_value : false_value |
التعبير الثلاثي | من اليسار إلى اليمين |
البيانات في رموز المصادقة
قد يحتوي الكائن 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 |
وقت الإصدار | الوقت الحالي، بالثواني منذ بدء حساب الفترة في نظام التشغيل UNIX |
exp |
وقت انتهاء الصلاحية |
الوقت الذي تنتهي فيه صلاحية الرمز المميّز، بالثواني منذ بدء حساب الفترة في نظام التشغيل UNIX يمكن أن يكون بعد 3600 ثانية كحدّ أقصى من iat .
ملاحظة: يتحكّم هذا الإعداد فقط في وقت انتهاء صلاحية الرمز المميّز المخصّص نفسه. ولكن بعد تسجيل دخول المستخدم باستخدام signInWithCustomToken() ، سيظل مسجّلاً الدخول إلى الجهاز إلى أن تصبح جلسته غير صالحة أو يسجّل المستخدم خروجه.
|
<claims> (اختياري) |
مطالبات مخصّصة اختيارية لتضمينها في الرمز المميز، ويمكن الوصول إليها من خلال
auth.token (أو request.auth.token ) في
التعبيرات. على سبيل المثال، إذا أنشأت مطالبة مخصّصة
adminClaim ، يمكنك الوصول إليها باستخدام
auth.token.adminClaim .
|
ما هي الخطوات التالية؟
- توفّر Firebase Data Connect حزمة SDK للمشرف تتيح لك تنفيذ عمليات البحث والتعديل من بيئات ذات امتيازات.
- يمكنك الاطّلاع على معلومات حول أمان إدارة الهوية وإمكانية الوصول في دليل إدارة الخدمات وقواعد البيانات.