1. نظرة عامة
تهدف سلسلة الدروس التطبيقية حول الترميز بدون خادم (البرامج التعليمية العملية) والفيديوهات ذات الصلة إلى مساعدة مطوّري Google Cloud الذين لا يستخدمون خوادم على تحديث تطبيقاتهم من خلال إرشادهم خلال عملية واحدة أو أكثر من عمليات نقل البيانات، بعيدًا عن الخدمات القديمة في المقام الأول. يؤدي ذلك إلى تسهيل حمل التطبيقات وتوفير المزيد من الخيارات والمرونة، ما يتيح لك الدمج مع مجموعة أكبر من منتجات Cloud والوصول إليها والترقية بسهولة إلى الإصدارات الأحدث باللغات. مع تركيزنا في البداية على مستخدمي Cloud الأوائل، لا سيما مطوّري App Engine (البيئة العادية)، فإنّ هذه السلسلة واسعة بما يكفي لتشمل أنظمة أساسية أخرى بدون خادم، مثل Cloud Functions وCloud Run أو أي منصة أخرى إن وُجدت.
الغرض من هذا الدرس التطبيقي حول الترميز هو توضيح كيفية الانتقال من واجهة برمجة التطبيقات/خدمة مستخدمي App Engine إلى منصة Cloud Identity (GCIP) لمطوّري Python. هناك أيضًا نقل ضمني من NDB في App Engine إلى Cloud NDB للوصول إلى مخزن البيانات (يتم تناوله بشكل أساسي في وحدة نقل البيانات 2)، بالإضافة إلى الترقية إلى Python 3.
تتناول الوحدة 20 كيفية إضافة استخدام واجهة برمجة تطبيقات المستخدمين إلى نموذج تطبيق الوحدة 1. في هذه الوحدة، عليك استخدام تطبيق الوحدة 20 المكتمل ونقل استخدامه إلى Cloud Identity Platform.
ستتعرَّف على كيفية إجراء ما يلي:
- استبدال استخدام خدمة مستخدمي App Engine بـ Cloud Identity Platform
- استبدال استخدام اتفاقية عدم العمل في App Engine بـ Cloud NDB (راجع أيضًا الوحدة 2)
- إعداد موفّري هوية مصادقة مختلفين باستخدام مصادقة Firebase
- استخدام Cloud Resource Manager API للحصول على معلومات إدارة الهوية وإمكانية الوصول الخاصة بالمشروع
- استخدام حزمة تطوير البرامج (SDK) لمشرف Firebase للحصول على معلومات المستخدمين
- نقل نموذج التطبيق إلى Python 3
المتطلبات
- مشروع Google Cloud Platform مع حساب فوترة نشط على Google Cloud Platform
- المهارات الأساسية في لغة بايثون
- المعرفة العملية بأوامر نظام التشغيل Linux الشائعة
- معرفة أساسية حول تطوير ونشر تطبيقات App Engine
- نموذج تطبيق Module 20 App Engine قيد التشغيل
استطلاع
كيف ستستخدم هذا البرنامج التعليمي؟
كيف تقيّم تجربتك مع Python؟
ما هو تقييمك لتجربتك في استخدام خدمات Google Cloud؟
2. الخلفية
خدمة "مستخدمو App Engine" هي نظام لمصادقة المستخدم تستخدمه تطبيقات App Engine. ويوفّر التطبيق تسجيل الدخول بحساب Google كموفِّر للهوية، كما يوفّر روابط ملائمة لتسجيل الدخول وتسجيل الخروج للاستخدام في التطبيقات، كما يتوافق مع مفهوم المستخدمين المشرفين والوظائف المرتبطة بالمشرفين فقط. لتحسين إمكانية نقل التطبيقات، تنصح Google Cloud بالانتقال من خدمات App Engine القديمة إلى الخدمات المستقلة في Cloud، على سبيل المثال، من خدمة "المستخدمون" إلى "منصة Cloud Identity"، من بين خدمات أخرى.
تستند Identity Platform إلى مصادقة Firebase، وتضيف عددًا من ميزات المؤسسة، بما في ذلك المصادقة المتعدّدة العوامل وOIDC يتوفر دعم الدخول المُوحَّد (SSO) المستند إلى SAML، وإقامة متعددة، واتفاقية مستوى الخدمة بنسبة 99.95%، والمزيد. يتم أيضًا إبراز هذه الاختلافات في صفحة مقارنة المنتجات في "منصة الهوية" و"مصادقة Firebase". يتمتع كلا المنتجين بميزات أكثر بكثير من الوظائف التي تقدمها خدمة المستخدمين.
يوضح الدرس التطبيقي حول ترميز الوحدة 21 هذا تبديل مصادقة مستخدم التطبيق من خدمة "المستخدمين" إلى ميزات "نظام أساسي للهوية" التي تعكس بشكلٍ وثيق الوظائف الموضّحة في الوحدة 20. تعرض الوحدة 21 أيضًا النقل من NDB App Engine إلى Cloud NDB للوصول إلى مخزن البيانات، مع تكرار نقل بيانات الوحدة 2.
في حين أن رمز الوحدة 20 معلَن عنه باعتباره نموذجًا لتطبيق Python 2، يكون المصدر نفسه متوافقًا مع Python 2 و3، ويبقى على هذا النحو حتى بعد النقل إلى Identity Platform (وCloud NDB) هنا في الوحدة 21. من الممكن مواصلة استخدام خدمة "المستخدِمون" أثناء الترقية إلى Python 3 لأنّ النقل إلى Identity Platform أمر اختياري. يمكنك الاطّلاع على الدرس التطبيقي حول ترميز الوحدة 17 والفيديو لمعرفة كيفية مواصلة استخدام الخدمات المجمّعة أثناء الترقية إلى بيئات تشغيل الجيل الثاني مثل Python 3.
يتضمن هذا الدليل التوجيهي الخطوات التالية:
- الإعداد/التمهيد
- تعديل الإعدادات
- تعديل رمز التطبيق
3- الإعداد/التمهيد
يوضّح هذا القسم كيفية تنفيذ ما يلي:
- إعداد مشروعك على Google Cloud
- الحصول على نموذج تطبيق أساسي
- (إعادة) نشر التطبيق الأساسي والتحقّق من صحته
- تفعيل خدمات Google Cloud/واجهات برمجة التطبيقات الجديدة
تضمن هذه الخطوات البدء باستخدام رمز برمجي جاهز لنقل البيانات إلى خدمات Cloud المستقلة.
1. إعداد المشروع
إذا أكملت الدرس التطبيقي حول الترميز الخاص بالوحدة 20، أعِد استخدام المشروع نفسه (والرمز البرمجي). ويمكنك بدلاً من ذلك إنشاء مشروع جديد أو إعادة استخدام مشروع حالي آخر. تأكَّد من أنّ المشروع يتضمّن حساب فوترة نشطًا وتطبيق App Engine مفعَّل. ابحث عن رقم تعريف مشروعك واحتفِظ به خلال هذا الدرس التطبيقي حول الترميز واستخدِمه عندما تصادف متغيّر PROJ_ID
.
2. الحصول على نموذج تطبيق أساسي
ويتمثّل أحد المتطلّبات الأساسية في تطبيق Module 20 App Engine قيد التشغيل، لذلك عليك إما إكمال الدرس التطبيقي حول الترميز (الإجراء المقترَح، الرابط أعلاه) أو نسخ رمز الوحدة 20 من المستودع. وسواء كنت تستخدم نظامك أو استخدامك، هذا هو المكان الذي سنبدأ فيه ("البدء"). يرشدك الدرس التطبيقي حول الترميز خلال عملية النقل، وختامًا باستخدام رمز يشبه ما هو في مجلد Repo للوحدة 21 ("FINISH").
- بدء: مجلد الوحدة 20 (لغة بايثون 2)
- FINISH: الوحدة النمطية 21 مجلدات ( Python 2 أو Python 3)
- المستودع بالكامل (لنسخ ملف ZIP أو تنزيله)
انسخ مجلد Repo للوحدة 20. من المفترض أن يظهر لك الناتج أدناه، وقد يحتوي على مجلد lib
إذا كنت قد نفّذت الدرس التطبيقي الخاص بالوحدة 20:
$ ls README.md appengine_config.py templates app.yaml main.py requirements.txt
3- (إعادة) نشر التطبيق الأساسي والتحقّق من صحته
نفِّذ الخطوات التالية لنشر تطبيق الوحدة 20:
- احذف مجلد "
lib
" في حال توفّره وشغِّلpip install -t lib -r requirements.txt
لإعادة ملؤه. قد تحتاج إلى استخدامpip2
إذا قمت بتثبيت Python 2 و 3. - تأكَّد من تثبيت أداة سطر الأوامر
gcloud
وإعدادها ومراجعة استخدامها. - إذا كنت لا تريد إدخال
PROJ_ID
مع إصدار كل أمرgcloud
، عليك أولاً إعداد المشروع على Google Cloud باستخدامgcloud config set project
PROJ_ID
. - نشر نموذج التطبيق باستخدام "
gcloud app deploy
" - تأكَّد من أنّ التطبيق يعمل على النحو المتوقّع وبدون أخطاء. إذا أكملت الدرس التطبيقي حول الترميز الخاص بالوحدة 20، سيعرض التطبيق معلومات تسجيل الدخول للمستخدم (البريد الإلكتروني للمستخدم و"شارة المشرف" المحتملة وزر تسجيل الدخول/تسجيل الخروج) في أعلى الصفحة إلى جانب أحدث الزيارات (الموضّحة أدناه).
يؤدي تسجيل الدخول كمستخدم عادي إلى عرض عنوان البريد الإلكتروني للمستخدم و"تسجيل الدخول" تغير الزر إلى "تسجيل الخروج" الزر:
يؤدي تسجيل الدخول كمستخدم مشرف إلى عرض عنوان البريد الإلكتروني للمستخدم إلى جانب "(مشرف)" بجوارها:
4. تفعيل واجهات برمجة تطبيقات/خدمات Google Cloud الجديدة
مقدمة
يستخدم تطبيق Module 20 كلاً من App Engine وواجهات برمجة تطبيقات المستخدمين، والخدمات المجمّعة التي لا تتطلب إعدادًا إضافيًا، ولكن خدمات السحابة الإلكترونية المستقلة تتطلب ذلك، وسيستخدم التطبيق المحدَّث كلاً من نظام Cloud Identity Platform وCloud Datastore (عبر مكتبة عملاء Cloud NDB). بالإضافة إلى ذلك، يجب استخدام واجهة برمجة تطبيقات Cloud Resource Manager لتحديد مستخدمي App Engine المشرفين.
التكلفة
- تحتوي App Engine وCloud Datastore على "مجانية دائمًا" حصص المحتوى، وطالما أنك لا تتجاوز هذه الحدود، لا يتم تحصيل أي رسوم منك مقابل إكمال هذا البرنامج التعليمي. يمكنك الاطّلاع أيضًا على صفحة أسعار App Engine وصفحة أسعار Cloud Datastore لمزيد من التفاصيل.
- إصدار فواتير استخدام Cloud Identity Platform بناءً على عدد المستخدمين النشطين شهريًا (MAUs) أو عمليات التحقُّق من المصادقة. بعض الإصدارات من "مجانًا" لكل نموذج استخدام. يمكنك الاطّلاع على صفحة الأسعار للحصول على مزيد من التفاصيل. بالإضافة إلى ذلك، على الرغم من أنّ App Engine وCloud Datastore يتطلبان الفوترة، إنّ استخدام GCIP في حد ذاته لا يتطلب تفعيل الفوترة طالما أنك لا تتجاوز حصصه اليومية غير المجدية، لذا ضع ذلك في الاعتبار بالنسبة إلى مشاريع Cloud التي لا تتطلّب الفوترة من خلال واجهات برمجة تطبيقات أو خدمات Cloud.
- ويمكن استخدام Cloud Resource Manager API مجانًا للجزء الأكبر وفقًا لصفحة الأسعار.
يمكن للمستخدمين تفعيل واجهات Cloud API من Cloud Console أو من سطر الأوامر (عبر الأمر gcloud
، وهو جزء من SDK للسحابة الإلكترونية)، حسب إعداداتك المفضّلة. لنبدأ بواجهات برمجة تطبيقات Cloud Resource Manager وCloud Resource Manager.
من Cloud Console
انتقِل إلى صفحة "مكتبة مدير واجهة برمجة التطبيقات" (للمشروع الصحيح) في Cloud Console، وابحث عن واجهة برمجة تطبيقات باستخدام شريط البحث.
تفعيل واجهات برمجة التطبيقات هذه:
ابحث عن الزر تفعيل لكل واجهة برمجة تطبيقات بشكل منفصل وانقر عليه، وقد يُطلب منك إدخال معلومات الفوترة. على سبيل المثال، في ما يلي صفحة Resource Manager API:
يتغيّر الزرّ إلى "إدارة" عندما يكون مفعّلاً (بعد بضع ثوانٍ عادةً):
يمكنك تفعيل خدمة "تخزين البيانات في السحابة الإلكترونية" بالطريقة نفسها:
من سطر الأوامر
على الرغم من أنه من المفيد بصريًا تمكين واجهات برمجة التطبيقات من وحدة التحكم، إلا أن البعض يفضل سطر الأوامر. وهي ميزة إضافية تتيح لك تفعيل أيّ عدد من واجهات برمجة التطبيقات في آنٍ واحد. أصدر هذا الأمر لتفعيل كل من واجهة برمجة تطبيقات Cloud Resource Manager وCloud Resource Manager وانتظِر حتى تكتمل العملية، كما هو موضَّح في ما يلي:
$ gcloud services enable cloudresourcemanager.googleapis.com datastore.googleapis.com Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.
قد يُطلَب منك إدخال معلومات الفوترة.
"عناوين URL" تسمى أسماء الخدمات لواجهة برمجة التطبيقات المستخدمة في الأمر أعلاه، ويمكن العثور عليها أسفل صفحة المكتبة لكل واجهة برمجة تطبيقات. إذا كنت تريد تفعيل واجهات برمجة تطبيقات Cloud أخرى لتطبيقاتك، يمكنك العثور على أسماء الخدمات الخاصة بها في صفحات واجهة برمجة التطبيقات المقابلة لها. يسرد هذا الأمر جميع أسماء الخدمات لواجهات برمجة التطبيقات التي يمكنك تفعيلها:
gcloud services list
--available --filter="name:googleapis.com"
بعد إكمال الخطوات المذكورة أعلاه في Cloud Console أو في سطر الأوامر، يمكن للنموذج الآن الوصول إلى واجهات برمجة التطبيقات هذه. تتمثل الخطوات التالية في تفعيل Cloud Identity Platform وإجراء التغييرات اللازمة على الرمز.
تفعيل وإعداد Cloud Identity Platform (وحدة تحكُّم Cloud فقط)
Cloud Identity Platform هي خدمة في السوق لأنّها ترتبط بمورد خارج Google Cloud أو تعتمد عليه، مثل مصادقة Firebase. في الوقت الحالي، يمكنك تفعيل خدمات Marketplace فقط من Cloud Console. يُرجى اتّباع الخطوات التالية:
- انتقِل إلى صفحة Cloud Identity Platform في Cloud Marketplace وانقر على الزر تفعيل هناك. الترقية من مصادقة Firebase إذا طُلب منك ذلك، يؤدي ذلك إلى فتح قفل ميزات إضافية، مثل الميزات الموضّحة سابقًا في قسم الخلفية. في ما يلي صفحة Marketplace التي تبرز الزر تفعيل:
- بعد تفعيل "نظام أساسي للهوية"، قد يتم نقلك تلقائيًا إلى صفحة موفّرو الهوية. إذا لم يكن الأمر كذلك، يمكنك استخدام هذا الرابط المناسب للوصول إلى هناك.
- فعِّل موفِّر مصادقة Google. إذا لم يتم إعداد أي مقدّمي خدمة، انقر على إضافة مقدّم خدمة واختَر Google. عند الرجوع إلى هذه الشاشة، من المفترض أن يكون الإدخال Google مفعَّلاً. Google هو موفِّر المصادقة الوحيد الذي نستخدمه في هذا البرنامج التعليمي لمحاكاة خدمة مستخدمي App Engine كخدمة تسجيل دخول بسيطة من Google. في تطبيقاتك الخاصة، يمكنك تفعيل مقدّمي خدمات مصادقة إضافيين.
- بعد اختيار Google وموفِّري المصادقة الآخرين المطلوبين وإعدادهم، انقر على تفاصيل إعداد التطبيق، ومن نافذة مربّع حوار التأكيد، انسخ العنصرَين
apiKey
وauthDomain
في العنصرconfig
في علامة تبويب "الويب"، واحفظهما في مكان آمن. لمَ لا تنسخ كلّها؟ المقتطف في مربع الحوار هذا يتضمن ترميزًا ثابتًا وتاريخه، لذا ما عليك سوى حفظ أهم وحدات البت واستخدامها في الرمز الخاص بنا مع الاستخدام المتزامن لمصادقة Firebase. بعد نسخ القيم وحفظها في مكان آمن، انقر على الزر إغلاق، مع استكمال جميع الإعدادات اللازمة.
4. تعديل الإعدادات
تشمل التعديلات في الإعدادات كلاً من تغيير ملفات إعداد مختلفة، بالإضافة إلى إنشاء مكافئ لـ App Engine ولكن ضمن منظومة Cloud Identity Platform المتكاملة.
appengine_config.py
- في حال الترقية إلى Python 3، يجب حذف
appengine_config.py
- إذا كنت تخطّط للترقية إلى Identity Platform مع الاستمرار في استخدام Python 2، لا تحذف الملف. بدلاً من ذلك، سنقوم بتحديثه لاحقًا أثناء عملية الإقلاع في Python 2.
requirements.txt
تم إدراج ملف requirements.txt
للوحدة 20 فقط Flask. بالنسبة للوحدة 21، أضف الحزم التالية:
من المفترض أن يظهر محتوى requirements.txt
الآن على النحو التالي:
flask
google-auth
google-cloud-ndb
google-cloud-resource-manager
firebase-admin
app.yaml
- الترقية إلى Python 3 تعني تبسيط ملف
app.yaml
. أزِل كل شيء باستثناء توجيه وقت التشغيل، واضبط ذلك على إصدار متوافق حاليًا من Python 3. يستخدم المثال حاليًا الإصدار 3.10. - إذا كنت ستواصل استخدام Python 2، يجب عدم اتخاذ أي إجراء هنا بعد.
قبل:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
لا يحتوي نموذج الوحدة 20 على معالِجات ملفات ثابتة. إذا كانت تطبيقاتك تعمل، فاتركها كما هي. يمكنك إزالة جميع معالِجات النصوص البرمجية إذا أردت ذلك أو تركها هناك للرجوع إليها ما دمت تغيّر الأسماء المعرِّفة إلى auto
، كما هو موضَّح في دليل نقل بيانات app.yaml
. من خلال هذه التغييرات، تم تبسيط app.yaml
المُعدَّل للغة Python 3 من أجل:
بعد:
runtime: python310
تعديلات أخرى على الإعدادات
سواء كنت تستخدم Python 2 أو تنتقل إلى Python 3، إذا كان لديك مجلد lib
، احذفه.
5- تعديل رمز التطبيق
يعرض هذا القسم تعديلات على ملف التطبيق الرئيسي، main.py
، بدلاً من استخدام خدمة "مستخدمو App Engine" بـ Cloud Identity Platform. بعد تحديث التطبيق الرئيسي، ستحدّث نموذج الويب، templates/index.html
.
تحديث عمليات الاستيراد والإعداد
اتبع الخطوات أدناه لتحديث عمليات الاستيراد وتهيئة موارد التطبيقات:
- بالنسبة إلى عمليات الاستيراد، يجب استبدال App Engine NDB بـ Cloud NDB.
- يمكنك أيضًا استيراد Cloud Resource Manager من خلال Cloud NDB.
- تستند منصّة الهوية إلى مصادقة Firebase، لذا عليك استيراد حزمة تطوير البرامج (SDK) لمشرف Firebase.
- تتطلب واجهات برمجة التطبيقات في السحابة الإلكترونية استخدام برنامج واجهة برمجة التطبيقات، لذا يُرجى بدء استخدامها مع Cloud NDB في موضع أقل مباشرةً من عملية إعداد Flask.
على الرغم من استيراد حزمة Cloud Resource Manager هنا، سنستخدمها في مرحلة لاحقة أثناء إعداد التطبيق. في ما يلي عمليات الاستيراد والتهيئة من الوحدة 20 متبوعة بالشكل الذي يجب أن تتبعه الأقسام بعد تنفيذ التغييرات أعلاه:
قبل:
from flask import Flask, render_template, request
from google.appengine.api import users
from google.appengine.ext import ndb
app = Flask(__name__)
بعد:
from flask import Flask, render_template, request
from google.auth import default
from google.cloud import ndb, resourcemanager
from firebase_admin import auth, initialize_app
# initialize Flask and Cloud NDB API client
app = Flask(__name__)
ds_client = ndb.Client()
دعم مستخدمي مشرفي App Engine
هناك مكوّنان يمكن إضافتهما إلى التطبيق يتيحان التعرّف على المستخدمين المشرفين:
_get_gae_admins()
— لجمع مجموعة من المستخدمين المشرفين. تم الاتصال مرة واحدة وتم حفظهis_admin()
: يتحقّق مما إذا كان المستخدم الذي سجّل الدخول مستخدمًا مشرفًا. يتم استدعاؤه عند تسجيل دخول أي مستخدم
تطلب وظيفة الأداة، _get_gae_admins()
، واجهة برمجة تطبيقات "مدير الموارد" لجلب Cloud IAM allow-policy الحالية. تحدِّد سياسةallow-الأدوار وتفرضها على المسؤولين الرئيسيين (المستخدمون، وحسابات الخدمة، وغيرها). وتشمل عملية الإعداد ما يلي:
- جارٍ استرجاع رقم تعريف المشروع على Google Cloud (
PROJ_ID
) - إنشاء عميل واجهة برمجة تطبيقات Resource Manager (
rm_client
) - إنشاء مجموعة (للقراءة فقط) من أدوار مشرف App Engine (
_TARGETS
)
يتطلّب "مدير الموارد" رقم تعريف المشروع على السحابة الإلكترونية، لذا عليك استيراد google.auth.default()
وطلب تلك الدالة للحصول على رقم تعريف المشروع. يتميز هذا الاستدعاء بمَعلمة تبدو مثل عنوان URL ولكنها نطاق إذن OAuth2. عند تشغيل التطبيقات في السحابة الإلكترونية، على سبيل المثال، على جهاز افتراضي في Compute Engine أو تطبيق App Engine، يتم تقديم حساب خدمة تلقائي لديه امتيازات واسعة. وتماشيًا مع أفضل الممارسات المتمثلة في الحد الأدنى من الامتيازات، ننصحك بإنشاء حسابات الخدمة التي يديرها المستخدم.
بالنسبة إلى طلبات البيانات من واجهة برمجة التطبيقات، من الأفضل مزيدًا من تقليل نطاق تطبيقاتك إلى أدنى مستوى مطلوب للعمل بشكلٍ سليم. طلب البيانات من واجهة برمجة تطبيقات Resource Manager الذي سنجريه هو get_iam_policy()
الذي يحتاج إلى أحد النطاقات التالية لتشغيله:
https://www.googleapis.com/auth/cloud-platform
https://www.googleapis.com/auth/cloud-platform.read-only
https://www.googleapis.com/auth/cloudplatformprojects
https://www.googleapis.com/auth/cloudplatformprojects.readonly
لا يحتاج نموذج التطبيق إلا إذن بالقراءة فقط في سياسة مسموح به. لا يعدّل السياسة ولا يحتاج إلى الوصول إلى المشروع بأكمله. يعني ذلك أنّ التطبيق لا يحتاج إلى أيّ من الأذونات الثلاثة الأولى المطلوبة. الأمر الأخير هو كل ما هو مطلوب، وهذا ما نطبقه على نموذج التطبيق.
ينشئ النص الأساسي للدالة مجموعة فارغة من المستخدمين المشرفين (admins
)، ويسترجع allow_policy
من خلال get_iam_policy()
، ويكرر جميع عمليات الربط الخاصة به بحثًا تحديدًا عن أدوار مشرف App Engine:
roles/viewer
roles/editor
roles/owner
roles/appengine.appAdmin
بالنسبة إلى كل دور مستهدَف يتم العثور عليه، يعمل على تجميع المستخدمين الذين ينتمون إلى هذا الدور، وإضافتهم إلى المجموعة الإجمالية للمستخدمين المشرفين. وينتهي الأمر بعرض جميع المستخدمين المشرفين الذين تم العثور عليهم وتخزينهم مؤقتًا كقيم ثابتة (_ADMINS
) طوال فترة عمل هذا المثيل من App Engine. سنرى هذه المكالمة بعد قليل.
أضِف تعريف الدالة _get_gae_admins()
التالي إلى main.py
أسفل إنشاء مثيل برنامج Cloud NDB API (ds_client
):
def _get_gae_admins():
'return set of App Engine admins'
# setup constants for calling Cloud Resource Manager API
_, PROJ_ID = default( # Application Default Credentials and project ID
['https://www.googleapis.com/auth/cloudplatformprojects.readonly'])
rm_client = resourcemanager.ProjectsClient()
_TARGETS = frozenset(( # App Engine admin roles
'roles/viewer',
'roles/editor',
'roles/owner',
'roles/appengine.appAdmin',
))
# collate users who are members of at least one GAE admin role (_TARGETS)
admins = set() # set of all App Engine admins
allow_policy = rm_client.get_iam_policy(resource='projects/%s' % PROJ_ID)
for b in allow_policy.bindings: # bindings in IAM allow-policy
if b.role in _TARGETS: # only look at GAE admin roles
admins.update(user.split(':', 1).pop() for user in b.members)
return admins
عندما يسجّل المستخدمون الدخول إلى التطبيق، سيحدث ما يلي:
- يتم إجراء عملية تحقّق سريعة من نموذج الويب بعد أن يسجِّل المستخدم دخوله إلى Firebase.
- عندما تتغير حالة المصادقة في النموذج، يتم إجراء استدعاء
fetch()
بنمط Ajax إلى/is_admin
الذي يكون معالِجه هو الدالة التالية،is_admin()
. - يتم تمرير الرمز المميّز لمعرّف Firebase في نص POST إلى
is_admin()
، والذي يخرجه من الرؤوس ويستدعي حزمة تطوير البرامج (SDK) لمشرف Firebase للتحقّق من صحته. إذا كنت مستخدمًا صالحًا، يمكنك استخراج عنوان بريده الإلكتروني والتحقّق مما إذا كان مستخدمًا مشرفًا. - يتم بعد ذلك إرجاع النتيجة المنطقية إلى القالب كنتيجة 200 ناجحة.
إضافة is_admin()
إلى main.py
بعد _get_gae_admins()
مباشرةً:
@app.route('/is_admin', methods=['POST'])
def is_admin():
'check if user (via their Firebase ID token) is GAE admin (POST) handler'
id_token = request.headers.get('Authorization')
email = auth.verify_id_token(id_token).get('email')
return {'admin': email in _ADMINS}, 200
وتكون جميع الرموز البرمجية من كلتا الدالتين مطلوبة لتكرار الوظائف المتاحة من خدمة "المستخدمون"، وتحديدًا وظيفة is_current_user_admin()
الخاصة بها. قام استدعاء الدالة هذا في الوحدة رقم 20 بكل المهام الصعبة، على عكس الوحدة 21 حيث قمنا بتنفيذ حل بديل. والخبر السار هو أنّ التطبيق لم يعد يعتمد على خدمة App Engine فقط، ما يعني أنه يمكنك نقل تطبيقاتك إلى "التشغيل السحابي" أو غيرها من الخدمات. بالإضافة إلى ذلك، يمكنك أيضًا تغيير تعريف "المستخدم الإداري" لتطبيقاتك الخاصة من خلال التبديل إلى الأدوار المطلوبة في _TARGETS
، في حين تكون خدمة "المستخدمون" مضمَّنة بشكل ثابت في أدوار مشرف App Engine.
إعداد مصادقة Firebase والتخزين المؤقت لمستخدمي App Engine
كان بإمكاننا إعداد مصادقة Firebase في الجزء العلوي بالقرب من المكان نفسه الذي تم فيه إعداد تطبيق Flask وأنشأه عميل Cloud NDB API، ولكن لم تكن هناك حاجة إلى ذلك إلى أن يتمّ تحديد كل رموز المشرف، وهو ما وصلنا إليه الآن. وبالمثل، بعد أن تم تحديد _get_gae_admins()
، يمكنك طلبه لتخزين قائمة المستخدمين المشرفين مؤقتًا.
أضف هذه الأسطر أسفل نص دالة is_admin()
مباشرةً:
# initialize Firebase and fetch set of App Engine admins
initialize_app()
_ADMINS = _get_gae_admins()
الانتقال إلى تعديلات نماذج البيانات
ولن يتغيّر نموذج بيانات "Visit
". يتطلب الوصول إلى مخزن البيانات استخدامًا صريحًا لمدير سياق عميل Cloud NDB API، وهو ds_client.context()
. في الرموز البرمجية، يعني ذلك إكمال استدعاءات Datastore في كل من store_visit()
وfetch_visits()
داخل مجموعات Python with
. وهذا التحديث مماثل للوحدة 2. أجرِ التغييرات على النحو التالي:
قبل:
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
def store_visit(remote_addr, user_agent):
'create new Visit entity in Datastore'
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
def fetch_visits(limit):
'get most recent visits'
return Visit.query().order(-Visit.timestamp).fetch(limit)
بعد:
class Visit(ndb.Model):
'Visit entity registers visitor IP address & timestamp'
visitor = ndb.StringProperty()
timestamp = ndb.DateTimeProperty(auto_now_add=True)
def store_visit(remote_addr, user_agent):
'create new Visit entity in Datastore'
with ds_client.context():
Visit(visitor='{}: {}'.format(remote_addr, user_agent)).put()
def fetch_visits(limit):
'get most recent visits'
with ds_client.context():
return Visit.query().order(-Visit.timestamp).fetch(limit)
نقل منطق تسجيل دخول المستخدم إلى نموذج الويب
تتوفر خدمة "مستخدمو App Engine" من جهة الخادم، في حين أنّ "مصادقة Firebase" و"منصة Cloud Identity" هما بشكل أساسي من جهة العميل. ونتيجةً لذلك، يتم نقل الكثير من رموز إدارة المستخدمين في تطبيق الوحدة 20 إلى نموذج الويب للوحدة 21.
في main.py
، يمرر سياق الويب خمسة أجزاء أساسية من البيانات إلى النموذج، وترتبط العناصر الأربعة الأولى بإدارة المستخدمين وتختلف استنادًا إلى ما إذا كان المستخدم قد سجّل الدخول أم لا:
who
- عنوان البريد الإلكتروني للمستخدم في حال تسجيل الدخول أو المستخدم بخلاف ذلكadmin
: شارة (مشرف) إذا كان المستخدم الذي سجّل الدخول مشرفًاsign
: عرض زر تسجيل الدخول أو تسجيل الخروجlink
- روابط تسجيل الدخول أو تسجيل الدخول عند النقر على الزرvisits
— أحدث الزيارات
قبل:
@app.route('/')
def root():
'main application (GET) handler'
store_visit(request.remote_addr, request.user_agent)
visits = fetch_visits(10)
# put together users context for web template
user = users.get_current_user()
context = { # logged in
'who': user.nickname(),
'admin': '(admin)' if users.is_current_user_admin() else '',
'sign': 'Logout',
'link': '/_ah/logout?continue=%s://%s/' % (
request.environ['wsgi.url_scheme'],
request.environ['HTTP_HOST'],
), # alternative to users.create_logout_url()
} if user else { # not logged in
'who': 'user',
'admin': '',
'sign': 'Login',
'link': users.create_login_url('/'),
}
# add visits to context and render template
context['visits'] = visits # display whether logged in or not
return render_template('index.html', **context)
يتم نقل جميع عمليات إدارة المستخدمين إلى نموذج الويب، لذلك يتبقى لدينا الزيارات فقط، حيث تتم إعادة المعالج الرئيسي إلى ما كان عليه الأمر في تطبيق الوحدة الأولى:
بعد:
@app.route('/')
def root():
'main application (GET) handler'
store_visit(request.remote_addr, request.user_agent)
visits = fetch_visits(10)
return render_template('index.html', visits=visits)
تعديل نموذج الويب
كيف تبدو جميع التحديثات من القسم السابق في النموذج؟ نقل إدارة المستخدمين من التطبيق إلى مصادقة Firebase التي يتم تشغيلها في النموذج ومنفذ جزئي لكل هذا الرمز الذي نقلناه إلى JavaScript. ولاحظنا تقلصًا كبيرًا في main.py
، لذا نتوقع نموًا مشابهًا في templates/index.html
.
قبل:
<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
</head>
<body>
<p>
Welcome, {{ who }} <code>{{ admin }}</code>
<button id="logbtn">{{ sign }}</button>
</p><hr>
<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
<li>{{ visit.timestamp.ctime() }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>
<script>
document.getElementById("logbtn").onclick = () => {
window.location.href = '{{ link }}';
};
</script>
</body>
</html>
استبدل نموذج الويب بالكامل بالمحتويات أدناه:
بعد:
<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<script type="module">
// import Firebase module attributes
import {
initializeApp
} from "https://www.gstatic.com/firebasejs/9.10.0/firebase-app.js";
import {
GoogleAuthProvider,
getAuth,
onAuthStateChanged,
signInWithPopup,
signOut
} from "https://www.gstatic.com/firebasejs/9.10.0/firebase-auth.js";
// Firebase config:
// 1a. Go to: console.cloud.google.com/customer-identity/providers
// 1b. May be prompted to enable GCIP and upgrade from Firebase
// 2. Click: "Application Setup Details" button
// 3. Copy: 'apiKey' and 'authDomain' from 'config' variable
var firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_AUTH_DOMAIN",
};
// initialize Firebase app & auth components
initializeApp(firebaseConfig);
var auth = getAuth();
var provider = new GoogleAuthProvider();
//provider.setCustomParameters({prompt: 'select_account'});
// define login and logout button functions
function login() {
signInWithPopup(auth, provider);
};
function logout() {
signOut(auth);
};
// check if admin & switch to logout button on login; reset everything on logout
onAuthStateChanged(auth, async (user) => {
if (user && user != null) {
var email = user.email;
who.innerHTML = email;
logbtn.onclick = logout;
logbtn.innerHTML = "Logout";
var idToken = await user.getIdToken();
var rsp = await fetch("/is_admin", {
method: "POST",
headers: {Authorization: idToken}
});
var data = await rsp.json();
if (data.admin) {
admin.style.display = "inline";
}
} else {
who.innerHTML = "user";
admin.style.display = "none";
logbtn.onclick = login;
logbtn.innerHTML = "Login";
}
});
</script>
</head>
<body>
<p>
Welcome, <span id="who"></span> <span id="admin"><code>(admin)</code></span>
<button id="logbtn"></button>
</p><hr>
<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
<li>{{ visit.timestamp.ctime() }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>
<script>
var who = document.getElementById("who");
var admin = document.getElementById("admin");
var logbtn = document.getElementById("logbtn");
</script>
</body>
</html>
هناك العديد من المكونات في نص HTML هذا، لذا لنأخذها على حدة.
عمليات الاستيراد من Firebase
أثناء وجودك في عنوان مستند HTML، بعد تجاوز عنوان الصفحة، يمكنك استيراد مكونات Firebase المطلوبة. يتم الآن تقسيم مكوّنات Firebase إلى وحدات متعددة بهدف تحقيق الكفاءة. يتم استيراد الرمز المُخصّص لإعداد Firebase من وحدة تطبيق Firebase الرئيسية أثناء إدارة الوظائف التي تدير مصادقة Firebase، وGoogle بصفتها موفِّر المصادقة، وتسجيل الدخول والخروج، وتغيير حالة المصادقة "معاودة الاتصال". يتم استيرادها جميعًا من وحدة مصادقة Firebase:
<!doctype html>
<html>
<head>
<title>VisitMe Example</title>
<script type="module">
// import Firebase module attributes
import {
initializeApp
} from "https://www.gstatic.com/firebasejs/9.10.0/firebase-app.js";
import {
GoogleAuthProvider,
getAuth,
onAuthStateChanged,
signInWithPopup,
signOut
} from "https://www.gstatic.com/firebasejs/9.10.0/firebase-auth.js";
ضبط Firebase
في وقت سابق أثناء جزء إعداد نظام Identity Platform من هذا البرنامج التعليمي، كنت قد حفظت apiKey
وauthDomain
من مربّع الحوار تفاصيل إعداد التطبيق. أضِف تلك القيم إلى المتغيّر firebaseConfig
في هذا القسم التالي. يتوفر رابط في التعليقات لمزيد من التفاصيل:
// Firebase config:
// 1a. Go to: console.cloud.google.com/customer-identity/providers
// 1b. May be prompted to enable GCIP and upgrade from Firebase
// 2. Click: "Application Setup Details" button
// 3. Copy: 'apiKey' and 'authDomain' from 'config' variable
var firebaseConfig = {
apiKey: "YOUR_API_KEY",
authDomain: "YOUR_AUTH_DOMAIN",
};
إعداد Firebase
يبدأ القسم التالي في إعداد Firebase باستخدام معلومات الإعداد هذه.
// initialize Firebase app & auth components
initializeApp(firebaseConfig);
var auth = getAuth();
var provider = new GoogleAuthProvider();
//provider.setCustomParameters({prompt: 'select_account'});
يتيح ذلك إمكانية استخدام Google كموفِّر مصادقة، كما يوفّر خيارًا يتيح نشر أداة اختيار الحسابات حتى في حال تسجيل حساب Google واحد في جلسة المتصفِّح. بعبارة أخرى، عندما يكون لديك حسابات متعددة، يظهر لك "منتقي الحسابات" على النحو المتوقّع: ومع ذلك، إذا كان هناك مستخدم واحد فقط في الجلسة، تكتمل عملية تسجيل الدخول تلقائيًا بدون أي تفاعل من المستخدم. (تظهر النافذة المنبثقة ثم تختفي). يمكنك فرض ظهور مربّع الحوار لأداة اختيار الحساب لمستخدم واحد (مقارنةً بتسجيل الدخول إلى التطبيق على الفور) من خلال إلغاء تعليق سطر المَعلمة المخصّص. في حال تفعيل هذا الإعداد، تؤدي عمليات تسجيل الدخول لمستخدم واحد إلى إظهار أداة اختيار الحسابات:
وظائف تسجيل الدخول وتسجيل الخروج
تمثل السطور التالية من الرمز الدوال التي تتطلب نقرات تسجيل الدخول أو تسجيل الخروج:
// define login and logout button functions
function login() {
signInWithPopup(auth, provider);
};
function logout() {
signOut(auth);
};
إجراءات تسجيل الدخول وتسجيل الخروج
آخر قسم رئيسي في مجموعة <script>
هذه هو الوظيفة التي يتم طلبها لكل تغيير في المصادقة (تسجيل الدخول أو تسجيل الخروج).
// check if admin & switch to logout button on login; reset everything on logout
onAuthStateChanged(auth, async (user) => {
if (user && user != null) {
var email = user.email;
who.innerHTML = email;
logbtn.onclick = logout;
logbtn.innerHTML = "Logout";
var idToken = await user.getIdToken();
var rsp = await fetch("/is_admin", {
method: "POST",
headers: {Authorization: idToken}
});
var data = await rsp.json();
if (data.admin) {
admin.style.display = "inline";
}
} else {
who.innerHTML = "user";
admin.style.display = "none";
logbtn.onclick = login;
logbtn.innerHTML = "Login";
}
});
</script>
</head>
الرمز في الوحدة 20 الذي يحدد ما إذا كان يجب إرسال "مستخدم مسجّل الدخول" سياق النموذج مقابل "تسجيل خروج المستخدم" يتم نقل السياق هنا. ينتج عن الشرط المشروط في أعلى الصفحة true
إذا سجَّل المستخدم الدخول بنجاح، ما يؤدي إلى تنفيذ الإجراءات التالية:
- تم ضبط عنوان البريد الإلكتروني للمستخدم كي يتم عرضه.
- يتغيّر زر تسجيل الدخول إلى تسجيل الخروج.
- يتم إجراء اتصال بنمط Ajax إلى
/is_admin
لتحديد ما إذا كان سيتم عرض شارة المستخدم المشرف في(admin)
أم لا.
عندما يسجّل المستخدم خروجه، يتم تنفيذ عبارة else
لإعادة ضبط جميع معلومات المستخدم:
- تم ضبط اسم المستخدم على user.
- تمت إزالة أي شارة مشرف.
- تم تغيير زر تسجيل الخروج إلى تسجيل الدخول مرة أخرى.
متغيّرات النموذج
بعد انتهاء قسم العنوان، يبدأ النص الأساسي بمتغيرات النموذج التي يتم استبدالها بعناصر HTML التي تتغير حسب الضرورة:
- اسم المستخدم المعروض
- شارة مشرف
(admin)
(إذا كان ذلك منطبقًا) - زر تسجيل الدخول أو تسجيل الخروج
<body>
<p>
Welcome, <span id="who"></span> <span id="admin"><code>(admin)</code></span>
<button id="logbtn"></button>
</p><hr>
أحدث الزيارات ومتغيّرات عناصر HTML
لن يتغير رمز أحدث زيارات، وتضبط القطعة الأخيرة من <script>
المتغيّرات لعناصر HTML التي تتغيّر لتسجيل الدخول والخروج من القائمة أعلاه مباشرةً:
<h1>VisitMe example</h1>
<h3>Last 10 visits</h3>
<ul>
{% for visit in visits %}
<li>{{ visit.timestamp.ctime() }} from {{ visit.visitor }}</li>
{% endfor %}
</ul>
<script>
var who = document.getElementById("who");
var admin = document.getElementById("admin");
var logbtn = document.getElementById("logbtn");
</script>
</body>
</html>
يؤدي ذلك إلى إنهاء التغييرات المطلوبة في التطبيق ونموذج الويب للتبديل من NDB في App Engine وواجهات برمجة التطبيقات للمستخدمين إلى Cloud NDB و Identity Platform بالإضافة إلى الترقية إلى Python 3. تهانينا على الوصول إلى نموذج تطبيق الوحدة 21 الجديد. يتوفر الإصدار لدينا للمراجعة في مجلد مستودع الوحدة 21b.
الجزء التالي من الدرس التطبيقي حول الترميز اختياري (*) ويقتصر استخدامه على المستخدمين الذين يجب أن تظل تطبيقاتهم على Python 2، حيث يرشدك التطبيق إلى الخطوات اللازمة للوصول إلى تطبيق Python 2 Module 21 العامل.
6- *المنفذ الخلفي Python 2
هذا القسم الاختياري مخصَّص للمطوّرين الذين يُجرون عملية نقل بيانات على نظام Identity الأساسي، ولكن عليهم مواصلة العمل في بيئة تشغيل Python 2. وإذا لم يكن هذا الأمر يهمك، يمكنك تخطّي هذا القسم.
لإنشاء إصدار Python 2 صالح من تطبيق Module 21، تحتاج إلى ما يلي:
- متطلبات وقت التشغيل: ملفات الإعداد التي تتوافق مع Python 2 والتغييرات المطلوبة في التطبيق الرئيسي لتجنُّب حالات عدم توافق Python 3
- تغيير بسيط في المكتبة: تم إيقاف Python 2 نهائيًا قبل إضافة بعض الميزات المطلوبة إلى مكتبة برامج Resource Manager. وبالتالي، أنت بحاجة إلى طريقة بديلة للوصول إلى هذه الوظيفة المفقودة.
لنبدأ بهذه الخطوات الآن، بدءًا من عملية الإعداد.
استعادة appengine_config.py
في وقت سابق من هذا البرنامج التعليمي، تم إرشادك لحذف appengine_config.py
لأنه غير مستخدم في وقت تشغيل Python 3 App Engine. بالنسبة إلى Python 2، لا يجب الاحتفاظ بها فحسب، بل يجب تحديث الوحدة 20 appengine_config.py
لإتاحة استخدام مكتبات الجهات الخارجية المضمَّنة، وهي grpcio
وsetuptools
. تكون هذه الحزم مطلوبة عندما يستخدم تطبيق App Engine مكتبات عملاء Cloud، مثل مكتبات خدمات Cloud NDB وCloud Resource Manager.
ستضيف هذه الحِزم إلى "app.yaml
" بعد لحظات، ولكن يجب استدعاء الدالة pkg_resources.working_set.add_entry()
من "setuptools
" لكي يتمكّن تطبيقك من الوصول إليها. يسمح هذا الإجراء للمكتبات التابعة لجهات خارجية المنسوخة (المجمعة ذاتيًا أو التي يزوّدها مورّدون) والمثبّتة في مجلد lib
بالاتصال بالمكتبات المدمَجة.
يُرجى تنفيذ التعديلات التالية على ملف appengine_config.py
لتطبيق هذه التغييرات:
قبل:
from google.appengine.ext import vendor
# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
وهذا الرمز وحده لا يكفي لدعم استخدام setuptools
وgrpcio
. هناك حاجة إلى إضافة بضعة أسطر إضافية، لذا يجب تعديل appengine_config.py
ليظهر على النحو التالي:
بعد:
import pkg_resources
from google.appengine.ext import vendor
# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)
# Add libraries to pkg_resources working set to find the distribution.
pkg_resources.working_set.add_entry(PATH)
يمكن العثور على مزيد من التفاصيل حول التغييرات المطلوبة لإتاحة مكتبات عميل Cloud في مستندات نقل البيانات للخدمات المجمّعة.
app.yaml
على غرار الدالة appengine_config.py
، يجب إرجاع الملف app.yaml
إلى ملف يتوافق مع Python 2. لنبدأ بالوحدة الأصلية 20 app.yaml
:
قبل:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
بالإضافة إلى setuptools
وgrpcio
كما ذكرنا سابقًا، هناك عنصر تبعي (لا يرتبط بشكل صريح بنقل بيانات النظام الأساسي للهوية) يتطلّب استخدام مكتبة برامج Cloud Storage، وتحتاج إلى حزمة مدمجة أخرى تابعة لجهة خارجية، وهي ssl
. يمكنك إضافة العناصر الثلاثة في قسم libraries
جديد، مع اختيار "الأحدث". الإصدارات المتاحة من هذه الحزم إلى app.yaml
:
بعد:
runtime: python27
threadsafe: yes
api_version: 1
handlers:
- url: /.*
script: main.app
libraries:
- name: grpcio
version: latest
- name: setuptools
version: latest
- name: ssl
version: latest
requirements.txt
بالنسبة إلى الوحدة رقم 21، أضفنا مصادقة Google وCloud NDB وCloud Resource Manager وSDK لمشرف Firebase إلى Python 3 requirements.txt
. موقف بايثون 2 أكثر تعقيدًا:
- توفّر واجهة برمجة تطبيقات Resource Manager وظيفة "سياسة السماح" اللازمة لنموذج التطبيق. لم يكن هذا الدعم متوفّرًا حتى الآن في الإصدار الأخير من Python 2 من مكتبة برامج Cloud Resource Manager. (وهو متوفر فقط في إصدار Python 3).
- نتيجةً لذلك، يجب استخدام طريقة بديلة للوصول إلى هذه الميزة من خلال واجهة برمجة التطبيقات. يكمن الحل في استخدام مكتبة برامج Google APIs ذات المستوى الأدنى للتواصل مع واجهة برمجة التطبيقات. للتبديل إلى مكتبة البرامج هذه، عليك استبدال
google-cloud-resource-manager
بحزمةgoogle-api-python-client
ذات المستوى الأدنى. - نظرًا لإلغاء Python 2، يتطلب الرسم البياني للتبعية الذي يتوافق مع الوحدة 21 قفل حِزم معيّنة على إصدارات معيّنة. يجب استدعاء بعض الحزم حتى لو لم يتم تحديدها في بايثون 3
app.yaml
.
قبل:
flask
بدءًا من الوحدة رقم 20 requirements.txt
، يمكنك تحديثها إلى ما يلي لأي تطبيق يعمل في الوحدة 21:
بعد:
grpcio==1.0.0
protobuf<3.18.0
six>=1.13.0
flask
google-gax<0.13.0
google-api-core==1.31.1
google-api-python-client<=1.11.0
google-auth<2.0dev
google-cloud-datastore==1.15.3
google-cloud-firestore==1.9.0
google-cloud-ndb
google-cloud-pubsub==1.7.0
firebase-admin
سيتم تعديل أرقام الحِزم والإصدارات في المستودع عند تغيُّر التبعيات، إلا أنّ app.yaml
هذا يكفي لتطبيق يعمل على النحو المطلوب في وقت كتابة هذا النموذج.
تعديلات أخرى على الإعدادات
إذا لم يسبق لك حذف مجلد lib
في هذا الدرس التطبيقي حول الترميز، ننصحك بذلك الآن. باستخدام تطبيق "requirements.txt
" الذي تم تعديله مؤخرًا، عليك إصدار هذا الأمر المألوف لتثبيت هذه المتطلبات في "lib
":
pip install -t lib -r requirements.txt # or pip2
في حال تثبيت Python 2 و3 على نظام التطوير الذي تستخدمه، قد تحتاج إلى استخدام pip2
بدلاً من pip
.
تعديل رمز التطبيق
لحسن الحظ، تتوفر معظم التغييرات المطلوبة في ملفات الإعداد. التغيير الوحيد المطلوب في رمز التطبيق هو إجراء تحديث ثانوي لاستخدام مكتبة عملاء Google API ذات المستوى الأدنى بدلاً من مكتبة عملاء Resource Manager للوصول إلى واجهة برمجة التطبيقات. ما مِن تعديلات مطلوبة على نموذج الويب templates/index.html
.
تعديل عمليات الاستيراد والإعداد
استبدل مكتبة عملاء Resource Manager (google.cloud.resourcemanager
) بمكتبة برامج Google APIs (googleapiclient.discovery
)، كما هو موضح أدناه:
قبل:
from flask import Flask, render_template, request
from google.auth import default
from google.cloud import ndb, resourcemanager
from firebase_admin import auth, initialize_app
بعد:
from flask import Flask, render_template, request
from google.auth import default
from google.cloud import ndb
from googleapiclient import discovery
from firebase_admin import auth, initialize_app
الدعم لمستخدمي مشرفي App Engine
يجب إجراء بعض التغييرات في _get_gae_admins()
لإتاحة استخدام مكتبة البرامج ذات المستوى الأدنى. لنناقش التغييرات أولاً، ثم نمنحك كل الرموز للتحديث.
يتطلب رمز Python 2 استخدام كل من بيانات الاعتماد ورقم تعريف المشروع المعروض من google.auth.default()
. لا يتم استخدام بيانات الاعتماد في Python 3، لذا تم تخصيصها لمتغير وهمي عام ( _
). ونظرًا لأنها مطلوبة لإصدار Python 2، غيِّر الشرطة السفلية إلى CREDS
. وبدلاً من إنشاء عميل واجهة برمجة تطبيقات Resource Manager، ستنشئ نقطة نهاية خدمة لواجهة برمجة التطبيقات، وهي تشبه من حيث مفهوم عميل واجهة برمجة التطبيقات، لذلك نحتفظ باسم المتغير نفسه (rm_client
). يتمثل أحد الاختلافات في أن إنشاء مثيل لنقطة نهاية الخدمة يتطلب بيانات اعتماد (CREDS
).
وتظهر هذه التغييرات في الرمز أدناه:
قبل:
_, PROJ_ID = default( # Application Default Credentials and project ID
['https://www.googleapis.com/auth/cloudplatformprojects.readonly'])
rm_client = resourcemanager.ProjectsClient()
بعد:
CREDS, PROJ_ID = default( # Application Default Credentials and project ID
['https://www.googleapis.com/auth/cloud-platform'])
rm_client = discovery.build('cloudresourcemanager', 'v1', credentials=CREDS)
الفرق الآخر هو أنّ مكتبة برامج "مدير الموارد" تعرض كائنات سياسة السماح التي تستخدم تدوين السمة المنقّطة، في حين تعرض مكتبة البرامج ذات المستوى الأدنى قواميس Python حيث يتم استخدام الأقواس المربّعة ( [ ]
)، على سبيل المثال، يمكنك استخدام binding.role
لمكتبة عملاء "مدير الموارد" مقابل binding['role']
للمكتبة ذات المستوى الأدنى. تستخدم الطريقة الأولى أيضًا "underscore_Separate" الأسماء مقابل المكتبة ذات المستوى الأدنى وتفضيل "CamelCased" بالإضافة إلى طريقة مختلفة قليلاً لتمرير معلمات واجهة برمجة التطبيقات.
في ما يلي الاختلافات في الاستخدام:
قبل:
allow_policy = rm_client.get_iam_policy(resource='projects/%s' % PROJ_ID)
for b in allow_policy.bindings: # bindings in IAM allow-policy
if b.role in _TARGETS: # only look at GAE admin roles
admins.update(user.split(':', 1).pop() for user in b.members)
بعد:
allow_policy = rm_client.projects().getIamPolicy(resource=PROJ_ID).execute()
for b in allow_policy['bindings']: # bindings in IAM allow-policy
if b['role'] in _TARGETS: # only look at GAE admin roles
admins.update(user.split(':', 1).pop() for user in b['members'])
من خلال جمع كل هذه التغييرات معًا، استبدِل Python 3 _get_gae_admins()
بهذا الإصدار المكافئ من Python 2:
def _get_gae_admins():
'return set of App Engine admins'
# setup constants for calling Cloud Resource Manager API
CREDS, PROJ_ID = default( # Application Default Credentials and project ID
['https://www.googleapis.com/auth/cloud-platform'])
rm_client = discovery.build('cloudresourcemanager', 'v1', credentials=CREDS)
_TARGETS = frozenset(( # App Engine admin roles
'roles/viewer',
'roles/editor',
'roles/owner',
'roles/appengine.appAdmin',
))
# collate users who are members of at least one GAE admin role (_TARGETS)
admins = set() # set of all App Engine admins
allow_policy = rm_client.projects().getIamPolicy(resource=PROJ_ID).execute()
for b in allow_policy['bindings']: # bindings in IAM allow-policy
if b['role'] in _TARGETS: # only look at GAE admin roles
admins.update(user.split(':', 1).pop() for user in b['members'])
return admins
لا تحتاج الدالة is_admin()
إلى إجراء أي تعديلات لأنّها تعتمد على الإضافة _get_gae_admins()
التي سبق أن تم تعديلها.
وبهذا نكون قد انتهينا من إجراء التغييرات المطلوبة لنقل تطبيق Python 3 Module 21 إلى Python 2. تهانينا على الوصول إلى نموذج تطبيق الوحدة 21 المعدَّل. ستعثر على كل الرموز في مجلد الوحدة النمطية 21a repo.
7. الملخّص/تنظيف البيانات
إنّ الخطوات الأخيرة في الدرس التطبيقي حول الترميز هي التأكّد من أنّ المشرفين (المستخدمون أو حسابات الخدمة) الذين يشغلون هذا التطبيق لديهم الأذونات المناسبة لتنفيذ ذلك، ثم نشر التطبيق للتأكّد من أنّه يعمل على النحو المطلوب وظهور التغييرات في النتائج.
إمكانية الاطّلاع على سياسة السماح بإدارة الهوية وإمكانية الوصول
في وقت سابق، قدمنا لك الأدوار الأربعة المطلوبة للاعتراف بالمستخدم كمشرف في App Engine، ولكن هناك الآن وظيفة خامسة لتصبح على دراية بها:
roles/viewer
roles/editor
roles/owner
roles/appengine.appAdmin
roles/resourcemanager.projectIamAdmin
(للجهات الرئيسية التي يمكنها الوصول إلى سياسة السماح بإدارة الهوية وإمكانية الوصول)
يتيح الدور roles/resourcemanager.projectIamAdmin
للمسؤولين تحديد ما إذا كان المستخدم النهائي عضوًا في أي من أدوار مشرف App Engine. في حال عدم توفُّر العضوية في roles/resourcemanager.projectIamAdmin
، سيتعذّر تنفيذ طلبات البيانات إلى Cloud Resource Manager API للحصول على سياسة السماح.
ليس عليك اتخاذ أي إجراء صريح هنا لأنّ تطبيقك سيتم تشغيله ضمن حساب خدمة App Engine التلقائي الذي يتم منحه تلقائيًا عضوية في هذا الدور. حتى إذا كنت تستخدم حساب الخدمة التلقائي أثناء مرحلة التطوير، ننصحك بشدة بإنشاء حساب خدمة يديره المستخدم واستخدامه مع الحد الأدنى من الأذونات المطلوبة لكي يعمل التطبيق بشكلٍ سليم. لمنح عضوية لحساب الخدمة هذا، شغِّل الأمر التالي:
$ gcloud projects add-iam-policy-binding PROJ_ID --member="serviceAccount:USR_MGD_SVC_ACCT@PROJ_ID.iam.gserviceaccount.com" --role=roles/resourcemanager.projectIamAdmin
PROJ_ID
هو رقم تعريف المشروع على Google Cloud وUSR_MGD_SVC_ACCT@PROJ_ID.iam.gserviceaccount.com
هو حساب الخدمة الذي يديره المستخدم والذي تنشئه لتطبيقك. يؤدي هذا الأمر إلى إخراج سياسة "إدارة الهوية وإمكانية الوصول" المعدَّلة لمشروعك، حيث يمكنك التأكّد من اشتراك حساب الخدمة في roles/resourcemanager.projectIamAdmin
. لمزيد من المعلومات، اطّلِع على المستندات المرجعية. للتكرار، لست بحاجة إلى إصدار هذا الأمر في هذا الدرس التطبيقي حول الترميز، ولكن يمكنك حفظه كمرجع لتحديث تطبيقاتك الخاصة.
نشر التطبيق والتحقق منه
حمِّل تطبيقك إلى السحابة الإلكترونية باستخدام الأمر gcloud app deploy
العادي. وبعد النشر، من المفترض أن ترى الوظيفة تقريبًا مماثلة لتطبيق الوحدة 20 باستثناء أنك قد استبدلت خدمة مستخدمي App Engine بنجاح بنظام Cloud Identity Platform (ومصادقة Firebase) لإدارة المستخدمين:
أحد الاختلافات التي ستلاحظها مقارنةً بالوحدة 20 هو أن النقر على تسجيل الدخول يؤدي إلى ظهور نافذة منبثقة بدلاً من إعادة توجيه، كما تم التقاطها في بعض لقطات الشاشة أدناه. ومع ذلك، يختلف السلوك قليلاً حسب الوحدة 20 بناءً على عدد حسابات Google التي تم تسجيلها في المتصفح.
في حال لم يكن هناك مستخدمون مسجَّلون في المتصفّح أو مستخدم واحد لم يسجّل الدخول بعد، ستظهر نافذة منبثقة عامة لتسجيل الدخول باستخدام حساب Google:
في حال تسجيل مستخدم واحد من خلال المتصفّح، ولكنّه سجّل الدخول في مكان آخر، لن يظهر أي مربّع حوار (أو ينبثق ويغلق على الفور)، وينتقل التطبيق إلى حالة تسجيل الدخول (يعرض البريد الإلكتروني للمستخدم والزر تسجيل الخروج).
قد يرغب بعض المطوّرين في توفير أداة اختيار الحسابات، حتى لمستخدم واحد:
لتنفيذ ذلك، يجب إلغاء تعليق السطر provider.setCustomParameters({prompt: 'select_account'});
في نموذج الويب كما هو موضَّح سابقًا.
إذا كان هناك عدة مستخدمين، ينبثق مربّع حوار أداة اختيار الحسابات (انظر أدناه). إذا لم يكن المستخدم مسجّلاً الدخول بعد، سيُطلب منه ذلك. في حال سبق أن سجّلت الدخول، تختفي النافذة المنبثقة، ويصبح التطبيق مسجّلاً الدخول.
تبدو حالة تسجيل الدخول للوحدة 21 مطابقة لواجهة مستخدم الوحدة 20:
وينطبق ذلك أيضًا على الحالات التي سجَّل فيها مستخدم مشرف الدخول:
على عكس الوحدة 21، تصل الوحدة 20 دائمًا إلى منطق محتوى نموذج الويب من التطبيق (رمز من جهة الخادم). ومن عيوب الوحدة رقم 20 هو تسجيل زيارة واحدة عند نقر المستخدم على التطبيق لأول مرة، بينما يتم تسجيل زيارة أخرى عندما يقوم المستخدم بتسجيل الدخول.
بالنسبة إلى الوحدة رقم 21، يقع منطق تسجيل الدخول في نموذج الويب فقط (الرمز من جهة العميل). ليس هناك حاجة إلى رحلة من جهة الخادم لتحديد المحتوى الذي سيتم عرضه. ويُرجى العِلم بأنّ المكالمة الوحيدة التي يتم إجراؤها إلى الخادم هي التحقّق من المستخدمين المشرفين بعد تسجيل دخول المستخدم النهائي. وهذا يعني أن عمليات تسجيل الدخول والخروج لا تسجِّل زيارات إضافية، وبالتالي تظل قائمة الزيارات الأخيرة ثابتة لإجراءات إدارة المستخدم. لاحظ أن لقطات الشاشة أعلاه تعرض نفس المجموعة المكونة من أربع زيارات عبر معلومات تسجيل دخول متعددة للمستخدمين.
لقطات شاشة الوحدة 20 توضح "خطأ الزيارة المزدوجة" في بداية هذا الدرس التطبيقي حول الترميز. يتم عرض سجلات الزيارات المنفصلة لكل إجراء تسجيل دخول أو تسجيل خروج. تحقَّق من الطوابع الزمنية لآخر زيارة لكل لقطة شاشة تعرِض الترتيب الزمني.
تَنظيم
بنود عامة
إذا كنت قد انتهيت الآن، ننصحك بإيقاف تطبيق App Engine لتجنُّب تحمُّل تكلفة الفوترة. ومع ذلك، إذا أردت إجراء المزيد من الاختبارات أو التجارب، فمنصة App Engine لها حصة مجانية، ولن يتم تحصيل أي رسوم منك طالما أنك لا تتجاوز فئة الاستخدام هذه. هذه المعلومات متعلقة بالحوسبة، ولكن قد يتم أيضًا فرض رسوم على خدمات App Engine ذات الصلة، لذا يُرجى التحقق من صفحة الأسعار للحصول على مزيد من المعلومات. وإذا كانت عملية النقل هذه تشمل خدمات Cloud أخرى، يتم تحصيل الرسوم منها بشكل منفصل. وفي كلتا الحالتين، يمكنك الاطّلاع على قسم "الدروس التطبيقية حول الترميز" إذا كان ذلك منطبقًا. أدناه.
للإفصاح الكامل عن المعلومات، يتحمّل النشر على منصة حوسبة بدون خادم في Google Cloud مثل App Engine تكاليف بسيطة لإنشاء المحتوى وتخزينه. تمتلك خدمة Cloud Build حصتها المجانية الخاصة، كما هي الحال في Cloud Storage. يستهلك تخزين تلك الصورة بعضًا من هذه الحصة. ومع ذلك، قد تكون مقيمًا في منطقة لا يتوفر بها هذا المستوى المجاني، لذا عليك الانتباه إلى استخدام مساحة التخزين لتقليل التكاليف المحتملة. "مجلدات" محددة في Cloud Storage التي يجب عليك مراجعتها ما يلي:
console.cloud.google.com/storage/browser/LOC.artifacts.PROJECT_ID.appspot.com/containers/images
console.cloud.google.com/storage/browser/staging.PROJECT_ID.appspot.com
- تعتمد روابط مساحة التخزين أعلاه على
PROJECT_ID
وLOC
، على سبيل المثال "us
". إذا كان التطبيق مستضافًا في الولايات المتحدة الأمريكية
من ناحية أخرى، إذا كنت لا تريد مواصلة استخدام هذا التطبيق أو الدروس التطبيقية الأخرى ذات الصلة لنقل البيانات وأردت حذف جميع البيانات بالكامل، عليك إيقاف مشروعك.
خصوصيّة هذا الدرس التطبيقي حول الترميز
الخدمات المدرَجة أدناه هي خدمات فريدة لهذا الدرس التطبيقي حول الترميز. ارجع إلى وثائق كل منتج لمزيد من المعلومات:
- يتم تقديم خدمة مخزن بيانات App Engine من خلال Cloud Datastore (Cloud Firestore في وضع "مخزن البيانات") التي توفّر أيضًا فئة مجانية. يمكنك الاطّلاع على صفحة الأسعار لمزيد من المعلومات.
- ينطوي استخدام Cloud Identity Platform على مستوى معيّن من "الإصدار المجاني" بناءً على الخدمة التي تستخدمها. يمكنك الاطّلاع على صفحة الأسعار للحصول على مزيد من التفاصيل.
- ويمكن استخدام Cloud Resource Manager API مجانًا للجزء الأكبر وفقًا لصفحة الأسعار.
الخطوات التالية
بالإضافة إلى هذا البرنامج التعليمي، تشمل وحدات نقل البيانات الأخرى التي تركز على الانتقال من الخدمات المجمّعة القديمة التي يجب مراعاتها ما يلي:
- الوحدة 2: النقل من App Engine
ndb
إلى Cloud NDB - الوحدات 7-9: النقل من قائمة انتظار مهام App Engine (دفع المهام) إلى Cloud Tasks
- الوحدات 12-13: النقل من App Engine Memcache إلى Cloud Memorystore
- الوحدات 15-16: النقل من App Engine Blobstore إلى Cloud Storage
- الوحدات 18-19: النقل من قائمة انتظار مهام App Engine (سحب المهام) إلى Cloud Pub/Sub
لم يعد App Engine النظام الأساسي الوحيد بدون خوادم في Google Cloud. إذا كان لديك تطبيق App Engine صغير أو تطبيق ذو وظائف محدودة وتريد تحويله إلى خدمة مصغّرة مستقلة، أو إذا كنت تريد تقسيم تطبيق متجانس إلى عدة مكوّنات قابلة لإعادة الاستخدام، هذه هي الأسباب الوجيهة للانتقال إلى وظائف السحابة الإلكترونية. إذا أصبحت عملية التطوير جزءًا من سير عمل تطوير التطبيقات، خاصةً إذا كانت تتألف من مسار CI/CD (التكامل المستمر أو العرض أو النشر المستمر)، ننصحك بنقل البيانات إلى تشغيل السحابة الإلكترونية. تغطي الوحدات التالية هذه السيناريوهات:
- نقل البيانات من App Engine إلى Cloud Functions: راجِع الوحدة 11.
- نقل البيانات من App Engine إلى Cloud Run: راجِع الوحدة 4 لتضمين تطبيقك مع Docker، أو الوحدة 5 لتنفيذ ذلك بدون حاويات أو معلومات Docker أو
Dockerfile
s.
إنّ التبديل إلى نظام أساسي آخر بدون خادم هو إجراء اختياري، وننصحك بالتفكير في أفضل الخيارات لتطبيقاتك وحالات الاستخدام قبل إجراء أي تغييرات.
بغض النظر عن وحدة نقل البيانات التي تفكر فيها بعد ذلك، يمكن الوصول إلى كل محتوى محطة النقل بدون خادم (الدروس التطبيقية حول الترميز والفيديوهات ورمز المصدر [عند توفّره]) من خلال مستودع البرامج المفتوحة المصدر. يوفّر README
الخاص بالمستودع أيضًا إرشادات حول عمليات نقل البيانات التي يجب أخذها في الاعتبار وأي "طلب" ذي صلة. لوحدات النقل.
8. مراجع إضافية
في ما يلي مراجع إضافية لمطوّري البرامج الذين يستكشفون وحدة نقل البيانات هذه أو وحدات نقل البيانات ذات الصلة بها. يمكنك أدناه تقديم ملاحظات حول هذا المحتوى، والعثور على روابط تؤدي إلى الرمز البرمجي، ومستندات مختلفة قد تجدها مفيدة.
المشاكل/الملاحظات في الدروس التطبيقية حول الترميز
إذا وجدت أي مشاكل في هذا الدرس التطبيقي حول الترميز، يُرجى البحث عن مشكلتك أولاً قبل ملء النموذج. روابط للبحث وإنشاء مشاكل جديدة:
موارد نقل البيانات
يمكن العثور على روابط لمجلدات repo للوحدة 20 (START) والوحدة 21 (FINISH) في الجدول أدناه.
Codelab | Python 2 | Python 3 |
(لا ينطبق) | ||
الوحدة 21 (هذا الدرس التطبيقي حول الترميز) |
مراجع على الإنترنت
في ما يلي الموارد ذات الصلة بهذا البرنامج التعليمي:
Cloud Identity Platform وCloud Marketplace
- صفحة منتج "منصة الهوية"
- مصادقة Firebase
- صفحة مقارنة المنتجات في "منصة الهوية" و"مصادقة Firebase"
- معلومات تسعير النظام الأساسي للهوية
- حصص النظام الأساسي للهوية (والاستخدام بدون أدوات)
- إعداد موفّري النظام الأساسي للهوية
- صفحة منتج Cloud Marketplace
- صفحة "منصة الهوية" في Marketplace
Cloud Resource Manager وCloud IAM وحزمة تطوير البرامج (SDK) لمشرف Firebase
- صفحة منتج "مدير الموارد"
- معلومات الأسعار في "مدير الموارد"
- مكتبة برامج "مدير الموارد"
- نظرة عامة على Cloud IAM (الأدوار، والسياسات المسموح بها، وما إلى ذلك)
- حزمة تطوير البرامج (SDK) لمشرف Firebase (Python)
مستخدمو App Engine وApp Engine NDB وCloud NDB وCloud Datastore
- نظرة عامة على مستخدمي App Engine
- مستندات NDB في App Engine
- مستودع NDB في App Engine
- مكتبة برامج Cloud NDB
- مستودع NDB على السحابة الإلكترونية
- صفحة منتج "تخزين البيانات في السحابة الإلكترونية"
- معلومات أسعار تخزين البيانات في السحابة الإلكترونية
المراجع الأخرى لوحدة النقل
- مقدّمة عن وحدة نقل البيانات
- جميع "محطة النقل بدون خادم" الموارد
- مستندات نقل البيانات إلى Python 3
- الوحدة 17 لنقل البيانات "استخدام الخدمات المجمّعة في بيئات تشغيل الجيل الثاني" درس تطبيقي حول الترميز
- وحدة النقل 20 "إضافة خدمة مستخدمي App Engine إلى تطبيقات Flask" درس تطبيقي حول الترميز
نقل بيانات App Engine
- استخدام مكتبات تابعة لجهات خارجية في تطبيقات Python 2
- التغييرات على
app.yaml
في بيئات تشغيل الجيل الثاني (Python 3) - دليل نقل بيانات Cloud NDB
- محتوى نقل البيانات إلى Cloud NDB
منصة App Engine
- مستندات App Engine
- وقت تشغيل Python 2 App Engine (بيئة عادية)
- استخدام المكتبات المضمَّنة في App Engine على Python 2 App Engine
- وقت تشغيل Python 3 App Engine (بيئة عادية)
- الاختلافات بين Python 2 3 بيئات تشغيل App Engine (بيئة عادية)
- دليل نقل البيانات من الإصدار 2 إلى 3 من App Engine (البيئة العادية)
- معلومات حول الأسعار والحصص في App Engine
- إطلاق الجيل الثاني من منصة App Engine (2018)
- المقارنة بين الدرجة الأولى و منصات من الجيل الثاني
- إتاحة بيئات التشغيل القديمة على المدى الطويل
- نماذج نقل بيانات المستندات
- نماذج النقل التي ساهم بها المجتمع
SDK للسحاب
- حزمة تطوير البرامج (SDK) في Google Cloud
- أداة سطر الأوامر
gcloud
لحزمة تطوير البرامج (SDK) في السحابة الإلكترونية - تفعيل Google APIs وإيقافه
- مدير واجهة برمجة التطبيقات في Cloud Console (تفعيل/إيقاف واجهات برمجة التطبيقات)
- تفعيل Google APIs من خلال
gcloud
- إنشاء قائمة بواجهات Google APIs باستخدام
gcloud
معلومات أخرى عن السحابة الإلكترونية
- Python على Google Cloud
- مستندات مكتبات عملاء Python
- مستودعات مكتبات برامج Python
- "مجانية دائمًا" الفئة
- حزمة تطوير البرامج (SDK) للسحابة الإلكترونية
- أداة سطر الأوامر
gcloud
لحزمة تطوير البرامج (SDK) في السحابة الإلكترونية - جميع مستندات Google Cloud
الفيديوهات
- محطة نقل بدون خادم
- الاستكشافات بدون خادم
- الاشتراك في Google Cloud Tech
- الاشتراك في Google Developers
الترخيص
هذا العمل مرخّص بموجب رخصة المشاع الإبداعي 2.0 مع نسب العمل إلى مؤلف عام.