1. مقدمة
غالبًا ما تكون مصادقة مستخدمي تطبيق الويب أمرًا ضروريًا، وعادة ما تتطلب برمجة خاصة في التطبيق. بالنسبة إلى تطبيقات Google Cloud Platform، يمكنك تسليم هذه المسؤوليات إلى خدمة Identity-Aware Proxy. إذا كنت تريد تقييد الوصول إلى مستخدمين محدَّدين فقط، ما مِن تغييرات ضرورية على التطبيق. إذا احتاج التطبيق إلى معرفة هوية المستخدم (مثل الاحتفاظ بالإعدادات المفضَّلة للمستخدم من جهة الخادم)، يمكن أن يوفِّر Identity-Aware Proxy ذلك بأقل رمز برمجي للتطبيق.
ما هو Identity-Aware Proxy؟
Identity-Aware Proxy (IAP) هو خدمة من Google Cloud Platform تعترض طلبات الويب المُرسَلة إلى تطبيقك، وتصادق على المستخدم الذي يقدّم الطلب باستخدام "خدمة هوية Google"، ولا تسمح بإرسال الطلبات إلا إذا كانت واردة من مستخدم تسمح به. بالإضافة إلى ذلك، يمكنه تعديل عناوين الطلبات لتتضمن معلومات عن المستخدم الذي تمت مصادقته.
سيرشدك هذا الدرس التطبيقي حول الترميز خلال عملية إنشاء تطبيقك الخاص وتقييد الوصول إليه والحصول على هوية المستخدم من خلال الشراء داخل التطبيق.
ما ستقوم بإنشائه
في هذا الدرس التطبيقي حول الترميز، ستنشئ تطبيق ويب بسيطًا باستخدام Google App Engine، ثم تستكشف طرقًا مختلفة لاستخدام Identity-Aware Proxy لحظر الوصول إلى التطبيق وتقديم معلومات هوية المستخدم إليه. سينفّذ تطبيقك ما يلي:
|
المعلومات التي ستطّلع عليها
- كيفية كتابة ونشر تطبيق App Engine بسيط باستخدام Python 3.7
- كيفية تفعيل وإيقاف عمليات الشراء داخل التطبيق لتقييد الوصول إلى تطبيقك
- كيفية الحصول على معلومات هوية المستخدم من الشراء داخل التطبيق إلى تطبيقك
- كيفية التحقق من المعلومات بطريقة مشفّرة من خلال عمليات الشراء داخل التطبيق للحماية من الانتحال
المتطلبات
- متصفّح ويب حديث مثل Chrome
- معرفة أساسية بلغة البرمجة بايثون
يركّز هذا الدرس التطبيقي حول الترميز على Google App Engine والشراء داخل التطبيق. يتم مسح المفاهيم غير ذات الصلة وكتل الرموز ويتم توفيرها لك لنسخها ولصقها ببساطة.
2. بدء الإعداد
ستعمل في بيئة سطر أوامر Cloud Shell. ابدأ بفتح تلك البيئة وجلب عينة التعليمات البرمجية إليها.
إطلاق وحدة التحكّم وCloud Shell
في أعلى الجانب الأيمن من صفحة التمرين المعملي، انقر على الزر فتح Google Console. يجب تسجيل الدخول باستخدام اسم المستخدم وكلمة المرور الظاهرَين أسفل ذلك الزر. |
سيتم تنفيذ جميع الأوامر الواردة في هذا الدرس التطبيقي حول الترميز في Cloud Shell للمشروع الذي تم إنشاؤه وفتحه لك. افتح Cloud Shell من خلال النقر على رمز "تفعيل Cloud Shell" على يسار عنوان صفحة "وحدة التحكّم". سيسمح لك النصف السفلي من الصفحة بإدخال الأوامر وتشغيلها.يمكن تشغيل هذه الأوامر من جهاز الكمبيوتر الخاص بك، ولكن عليك أولاً تثبيت برامج التطوير اللازمة وإعدادها. تحتوي Cloud Shell على جميع الأدوات البرمجية التي تحتاج إليها. |
تنزيل الرمز
انقر على منطقة سطر الأوامر في Cloud Shell حتى تتمكن من كتابة الأوامر. أحضر التعليمة البرمجية من Github ثم غيّرها إلى مجلد التعليمات البرمجية:
git clone https://github.com/googlecodelabs/user-authentication-with-iap.git
cd user-authentication-with-iap
يحتوي هذا المجلد على مجلد فرعي واحد لكل خطوة من هذا الدرس التطبيقي. سيتم التغيير إلى المجلد الصحيح لتنفيذ كل خطوة.
3- الخطوة 1 - نشر التطبيق وحمايته من خلال الشراء داخل التطبيق
هذا تطبيق قياسي في App Engine مكتوب بلغة Python 3.7 يعرض ببساطة "مرحبًا، العالم" صفحة الترحيب. وسوف ننشره ونختبره، ثم نقيد الوصول إليه باستخدام الشراء داخل التطبيق.
مراجعة رمز التطبيق
غيِّر من مجلد المشروع الرئيسي إلى المجلد الفرعي 1-HelloWorld
الذي يحتوي على رمز لهذه الخطوة.
cd 1-HelloWorld
يوجد رمز التطبيق في ملف main.py
. وهو يستخدم إطار عمل الويب Flask للاستجابة لطلبات الويب باستخدام محتوى نموذج. يتوفّر ملف النموذج هذا في templates/index.html
، وتحتوي هذه الخطوة على رمز HTML عادي فقط. يحتوي ملف نموذج ثانٍ على مثال أساسي لسياسة الخصوصية في templates/privacy.html
.
هناك ملفان آخران: تعرض requirements.txt
جميع مكتبات Python غير التلقائية التي يستخدمها التطبيق، وتخبر أداة app.yaml
Google Cloud Platform بأنّ هذا التطبيق متوافق مع Python 3.7 App Engine.
يمكنك سرد كل ملف في Shell باستخدام الأمر cat، كما في:
cat main.py
أو يمكنك فتح محرِّر رموز Cloud Shell بالنقر على رمز القلم الرصاص في أعلى يسار نافذة Cloud Shell وفحص الرمز البرمجي بهذه الطريقة.
ولن تحتاج إلى تغيير أي ملفات لهذه الخطوة.
النشر في App Engine
نشر التطبيق الآن في بيئة App Engine العادية للغة Python 3.7
gcloud app deploy
قد يُطلب منك اختيار منطقة لنشر التطبيق فيها. اختَر أي متجر قريب منك يقول إنّه "يتوافق مع المستوى العادي". عندما يُطلب منك تحديد ما إذا كنت تريد المتابعة، أدخِل Y
للإجابة بنعم.
من المفترض أن يكتمل النشر بعد بضع دقائق، وستظهر لك رسالة تفيد بأنّه يمكنك عرض تطبيقك من خلال gcloud app browse
. أدخِل ذلك الأمر. إذا لم يتم فتح علامة تبويب جديدة في المتصفح، انقر على الرابط المعروض لفتحها في علامة تبويب جديدة، أو انسخها إلى علامة تبويب جديدة مفتوحة يدويًا إذا لزم الأمر. بما أنّ هذه هي المرة الأولى التي يتم فيها تشغيل هذا التطبيق، سيستغرق ظهور هذا التطبيق بضع ثوانٍ أثناء بدء تشغيل مثيل السحابة الإلكترونية، ومن المفترض أن تظهر لك النافذة التالية.
يمكنك فتح عنوان URL نفسه من أي جهاز كمبيوتر متصل بالإنترنت للاطّلاع على صفحة الويب هذه. لم يتم تقييد الوصول حتى الآن.
تقييد الوصول من خلال الشراء داخل التطبيق
في نافذة Cloud Console، انقر على رمز القائمة في أعلى يمين الصفحة، ثم انقر على "الأمان"، ثم على Identity-Aware Proxy. | |
بما أنّها المرة الأولى التي تفعّل فيها خيار مصادقة لهذا المشروع، ستظهر لك رسالة تفيد بأنّه يجب ضبط شاشة موافقة OAuth قبل أن تتمكّن من استخدام ميزة "الشراء داخل التطبيق". | |
انقر على زر "ضبط شاشة الموافقة". ستُفتح علامة تبويب جديدة لضبط شاشة الموافقة. |
املأ الفراغات المطلوبة بالقيم المناسبة:
اسم التطبيق | مثال على الشراء داخل التطبيق |
البريد الإلكتروني للحصول على الدعم | عنوان بريدك الإلكتروني. قد يتم ملؤها مسبقًا. |
النطاق المسموح به | جزء اسم المضيف في عنوان URL للتطبيق، على سبيل المثال iap-example-999999.appspot.com. ويمكنك رؤية هذا في شريط العناوين لصفحة ويب Hello World التي فتحتها سابقًا. لا تضمِّن علامة البدء |
رابط الصفحة الرئيسية للتطبيق | عنوان URL الذي استخدمته لعرض تطبيقك |
رابط سياسة خصوصية التطبيق | رابط صفحة الخصوصية في التطبيق، تمامًا مثل رابط الصفحة الرئيسية مع إضافة /privacy في نهايته |
انقر على حفظ. سيُطلب منك إنشاء بيانات اعتماد. لست بحاجة إلى إنشاء بيانات اعتماد لهذا الدرس التطبيقي حول الترميز، لذا يمكنك ببساطة إغلاق علامة تبويب المتصفّح هذه.
ارجع إلى صفحة Identity-Aware Proxy وأعِد تحميلها. ستظهر لك الآن قائمة بالموارد التي يمكنك حمايتها.انقر على زر التبديل في عمود "الشراء داخل التطبيق" في صف تطبيق App Engine لتفعيل عمليات الشراء داخل التطبيق. | |
ستظهر لك أسماء النطاقات التي ستتم حمايتها من خلال الشراء داخل التطبيق. انقر على "تفعيل". | |
افتح الآن علامة تبويب متصفّح وانتقِل إلى عنوان URL الخاص بتطبيقك. ستظهر لك شاشة "تسجيل الدخول باستخدام حساب Google" تتطلّب منك تسجيل الدخول للوصول إلى التطبيق. | |
تسجيل الدخول باستخدام حساب Google أو G Suite ستظهر لك شاشة تمنعك من الوصول. |
لقد نجحت في حماية تطبيقك باستخدام الشراء داخل التطبيق، ولكنك لم تخبر بعد الشراء بالحسابات التي يجب السماح بمرورها.
ارجع إلى صفحة Identity-Aware Proxy في وحدة التحكّم، وضَع علامة في مربّع الاختيار بجانب تطبيق App Engine، واطّلِع على الشريط الجانبي على يسار الصفحة. | |
يجب إضافة كل عنوان بريد إلكتروني (أو عنوان مجموعة Google أو اسم نطاق G Suite) يجب السماح له بالوصول كعضو. انقر على "إضافة عضو". أدخِل عنوان بريدك الإلكتروني، ثم اختَر دور "مستخدم تطبيق الويب Cloud IAP/IAP-Secured Web App" لتخصيصه لهذا العنوان. يمكنك إدخال المزيد من العناوين أو نطاقات G Suite بالطريقة نفسها. |
انقر على "حفظ". الرسالة "تم تعديل السياسة" في أسفل النافذة.
انتقِل مرّة أخرى إلى التطبيق وأعِد تحميل الصفحة. من المفترض أن يظهر لك تطبيق الويب الآن، لأنّك سجّلت الدخول من قبل باستخدام مستخدم فوّضته. ومع ذلك، قد تظهر الرسالة "ليست لديك إذن وصول". نظرًا لأن عمليات الشراء داخل التطبيق قد لا تعيد التحقق من التفويض. في هذه الحالة، قم بالخطوات التالية:
- افتح متصفّح الويب للوصول إلى عنوان الصفحة الرئيسية مع إضافة
/_gcp_iap/clear_login_cookie
إلى نهاية عنوان URL، كما فيhttps://iap-example-999999.appspot.com/_gcp_iap/clear_login_cookie
. - ستظهر لك شاشة جديدة "تسجيل الدخول باستخدام حساب Google" يظهر فيها حسابك. لا تنقر على الحساب. بدلاً من ذلك، انقر على استخدام حساب آخر، وأعد إدخال بيانات الاعتماد.
- تؤدي هذه الخطوات إلى إعادة التحقّق من داخل التطبيق من وصولك، ومن المفترض أن تظهر لك الآن الشاشة الرئيسية لتطبيقك.
إذا كان بإمكانك الوصول إلى متصفح آخر أو استخدام وضع التصفح المتخفي في متصفحك، وكان لديك حساب GMail أو G Suite آخر صالح، يمكنك استخدام هذا المتصفح للانتقال إلى صفحة تطبيقك وتسجيل الدخول باستخدام الحساب الآخر. ونظرًا لأنه لم يتم تفويض هذا الحساب، ستظهر رسالة الخطأ "ليس لديك إذن الوصول". الشاشة بدلاً من تطبيقك.
4. الخطوة 2: الوصول إلى معلومات هوية المستخدم
بعد حماية التطبيق من خلال الشراء داخل التطبيق، يمكنه استخدام معلومات الهوية التي يوفرها الشراء داخل التطبيق في عناوين طلبات الويب التي يمر من خلالها. في هذه الخطوة، سيحصل التطبيق على عنوان البريد الإلكتروني الخاص بالمستخدم الذي سجّل الدخول، بالإضافة إلى رقم تعريف مستخدم فريد دائم يتم تعيينه لهذا المستخدم من خلال خدمة Google Identity. سيتم عرض هذه البيانات للمستخدم في صفحة الترحيب.
هذه هي الخطوة رقم 2، وانتهت الخطوة الأخيرة مع فتح Cloud Shell في المجلد iap-codelab/1-HelloWorld
. انتقِل إلى المجلد الخاص بهذه الخطوة:
cd ~/iap-codelab/2-HelloUser
النشر في App Engine
نظرًا لأن النشر يستغرق بضع دقائق، ابدأ بنشر التطبيق في بيئة App Engine العادية لـ Python 3.7:
gcloud app deploy
عندما يُطلب منك تحديد ما إذا كنت تريد المتابعة، أدخِل Y للإجابة بنعم. من المفترض أن تكتمل عملية النشر خلال بضع دقائق. وأثناء الانتظار، يمكنك فحص ملفات التطبيق كما هو موضح أدناه.
عندما تكون عملية النشر جاهزة، ستظهر لك رسالة تفيد بأنّه يمكنك عرض تطبيقك باستخدام gcloud app browse
. أدخِل ذلك الأمر. وإذا لم يتم فتح علامة تبويب جديدة على المتصفح، انسخ الرابط المعروض وافتحه في علامة تبويب جديدة كالمعتاد. من المفترض أن تظهر لك صفحة مشابهة لما يلي:
قد تحتاج إلى الانتظار لبضع دقائق ريثما يحل الإصدار الجديد من تطبيقك محل الإصدار السابق. يُرجى إعادة تحميل الصفحة إذا لزم الأمر لعرض صفحة مشابهة لما سبق.
فحص ملفات التطبيق
يحتوي هذا المجلد على مجموعة الملفات نفسها كما هو موضَّح في الخطوة 1، ولكن تم تغيير ملفَين: main.py
وtemplates/index.html
. تم تغيير البرنامج لاسترداد معلومات المستخدم التي يوفرها الشراء داخل التطبيق في عناوين الطلبات، ويعرض النموذج الآن تلك البيانات.
هناك سطران في main.py
يحصلان على بيانات الهوية المقدَّمة من خلال الشراء داخل التطبيق:
user_email = request.headers.get('X-Goog-Authenticated-User-Email')
user_id = request.headers.get('X-Goog-Authenticated-User-ID')
تتوفّر عناوين X-Goog-Authenticated-User-
من خلال الشراء داخل التطبيق، وتكون الأسماء غير حساسة لحالة الأحرف، لذا يمكن تقديمها بأحرف صغيرة أو بأحرف كبيرة بالكامل إذا كان ذلك مفضّلاً. تتضمن عبارة Render_template الآن تلك القيم بحيث يمكن عرضها:
page = render_template('index.html', email=user_email, id=user_id)
يمكن أن يعرض نموذج index.html تلك القيم من خلال تضمين الأسماء في أقواس معقوفة مضاعفة:
Hello, {{ email }}! Your persistent ID is {{ id }}.
يتّضح مما سبق أنّ البيانات المقدَّمة تكون مسبوقة بالرمز accounts.google.com
:، مع عرض مصدر المعلومات. يمكن لتطبيقك إزالة كل العناصر وصولاً إلى علامة النقطتين الرأسيتين للحصول على القيم الأولية عند الحاجة.
إيقاف عمليات الشراء داخل التطبيق
ماذا يحدث لهذا التطبيق في حال إيقاف الشراء داخل التطبيق أو تجاوزه بطريقة ما (على سبيل المثال، في تطبيقات أخرى تعمل في المشروع نفسه على السحابة الإلكترونية)؟ يجب إيقاف الشراء داخل التطبيق لرؤيته.
في نافذة Cloud Console، انقر على رمز القائمة في أعلى يمين الصفحة، ثم انقر على "الأمان"، ثم على Identity-Aware Proxy. انقر على مفتاح تبديل الشراء داخل التطبيق بجانب تطبيق App Engine لإيقاف ميزة الشراء داخل التطبيق. |
سيتم تحذيرك من أنّ هذا الإجراء سيسمح لجميع المستخدمين بالوصول إلى التطبيق.
أعِد تحميل صفحة الويب الخاصة بالتطبيق. ومن المفترض أن تظهر لك الصفحة نفسها، ولكن بدون أي معلومات عن المستخدم:
نظرًا لأن التطبيق أصبح غير محمي الآن، يمكن للمستخدم إرسال طلب ويب بدا أنه تم تمريره من خلال الشراء داخل التطبيق. على سبيل المثال، يمكنك تشغيل أمر curl التالي من Cloud Shell لتنفيذ ذلك (استبدِل <your-url-here> بعنوان URL الصحيح لتطبيقك):
curl -X GET <your-url-here> -H "X-Goog-Authenticated-User-Email: totally fake email"
وسيتم عرض صفحة الويب في سطر الأوامر، وستبدو على النحو التالي:
<!doctype html> <html> <head> <title>IAP Hello User</title> </head> <body> <h1>Hello World</h1> <p> Hello, totally fake email! Your persistent ID is None. </p> <p> This is step 2 of the <em>User Authentication with IAP</em> codelab. </p> </body> </html>
ليست هناك طريقة يمكن للتطبيق من خلالها معرفة أنه قد تم إيقاف الشراء داخل التطبيق أو تجاوزه. بالنسبة للحالات التي يمثل فيها هذا خطرًا محتملاً، تُظهر الخطوة 3 الحل.
5- الخطوة 3: استخدام التحقق من التشفير
وفي حال احتمال إيقاف عمليات الشراء داخل التطبيق أو تجاوزها، يمكن لتطبيقك التحقّق من صحة معلومات الهوية التي يتلقّاها. يستخدم هذا رأس طلب ويب ثالث تمت إضافته من خلال الشراء داخل التطبيق، ويُطلق عليه X-Goog-IAP-JWT-Assertion
. قيمة العنوان هي كائن موقَّع بطريقة مشفّرة ويحتوي أيضًا على بيانات هوية المستخدم. يمكن لتطبيقك التحقق من التوقيع الرقمي واستخدام البيانات المقدمة في هذا العنصر للتأكد من أنه تم توفيره من خلال الشراء داخل التطبيق بدون أي تعديل.
يتطلب إثبات صحة التوقيع الرقمي عدة خطوات إضافية، مثل استرداد أحدث مجموعة من مفاتيح Google العامة. يمكنك تحديد ما إذا كان تطبيقك يحتاج إلى هذه الخطوات الإضافية بناءً على مخاطر احتمالية أن يتمكن شخص ما من إيقاف الشراء داخل التطبيق أو تجاوزه، وحساسية التطبيق.
هذه هي الخطوة رقم 3، وانتهت الخطوة الأخيرة مع فتح Cloud Shell في المجلد iap-codelab/2-HelloUser
. انتقِل إلى المجلد الخاص بهذه الخطوة:
cd ~/iap-codelab/3-HelloVerifiedUser
النشر في App Engine
انشر التطبيق في بيئة App Engine العادية للغة Python 3.7:
gcloud app deploy
عندما يُطلب منك تحديد ما إذا كنت تريد المتابعة، أدخِل Y للإجابة بنعم. من المفترض أن تكتمل عملية النشر خلال بضع دقائق. وأثناء الانتظار، يمكنك فحص ملفات التطبيق كما هو موضح أدناه.
عندما تكون عملية النشر جاهزة، ستظهر لك رسالة تفيد بأنّه يمكنك عرض تطبيقك باستخدام gcloud app browse
. أدخِل ذلك الأمر. وإذا لم يتم فتح علامة تبويب جديدة على المتصفح، انسخ الرابط المعروض وافتحه في علامة تبويب جديدة كالمعتاد.
تذكر أنك قد أوقفت الشراء داخل التطبيق في الخطوة 2، لذلك لا يتم تقديم بيانات الشراء داخل التطبيق للتطبيق. من المفترض أن تظهر لك صفحة مشابهة لما يلي:
وكما حدث في السابق، قد تحتاج إلى الانتظار لبضع دقائق حتى يتم نشر أحدث نسخة لكي تظهر لك النسخة الجديدة من الصفحة.
لا تتوفر أي معلومات للمستخدم نظرًا لإيقاف ميزة الشراء داخل التطبيق. يمكنك الآن إعادة تفعيل ميزة الشراء داخل التطبيق.
في نافذة Cloud Console، انقر على رمز القائمة في أعلى يمين الصفحة، ثم انقر على "الأمان"، ثم على Identity-Aware Proxy. انقر على مفتاح تبديل الشراء داخل التطبيق بجانب تطبيق App Engine لتفعيل عمليات الشراء داخل التطبيق مرة أخرى. |
إعادة تحميل الصفحة يُفترض أن تظهر الصفحة على النحو التالي:
يُرجى العلم أنّ عنوان البريد الإلكتروني الذي قدّمته من خلال الطريقة التي تم إثبات ملكيتها لا يحتوي على البادئة accounts.google.com:
.
في حال إيقاف عمليات الشراء داخل التطبيق أو تجاوزها، قد تكون البيانات التي تم إثبات صحتها غير متوفّرة أو غير صالحة، لأنّه لا يمكن أن تحتوي على توقيع صالح ما لم ينشئها مالك مفاتيح Google الخاصة.
فحص ملفات التطبيق
يحتوي هذا المجلد على مجموعة الملفات نفسها كما هو موضَّح في الخطوة 2، مع تعديل ملفَّين وملف واحد جديد. الملف الجديد هو auth.py
، ويوفر طريقة user()
لاسترداد معلومات الهوية الموقَّعة بطريقة مشفَّرة والتحقُّق منها. الملفان الذي تم تغييرهما هما main.py
وtemplates/index.html
، ويستخدمان الآن نتائج هذه الطريقة. ويتم أيضًا عرض العناوين التي لم يتم التحقّق منها كما هو موضّح في الخطوة 2 للمقارنة.
تتوفر الوظيفة الجديدة بشكل أساسي في الدالة user()
:
def user():
assertion = request.headers.get('X-Goog-IAP-JWT-Assertion')
if assertion is None:
return None, None
info = jwt.decode(
assertion,
keys(),
algorithms=['ES256'],
audience=audience()
)
return info['email'], info['sub']
بيانات assertion
هي البيانات الموقّعة بطريقة مشفّرة والتي يتم تقديمها في عنوان الطلب المحدّد. يستخدم الرمز مكتبة للتحقق من صحة تلك البيانات وفك ترميزها. من خلال عملية التحقّق، يتم استخدام المفاتيح العامة التي توفّرها Google للتحقّق من البيانات التي يتم توقيعها، ومعرفة الجمهور الذي تم إعداد البيانات له (وهو مشروع Google Cloud المحمي). تجمع الدالتان المساعدتان keys()
وaudience()
هذه القيم وتعرضها.
يحتوي العنصر الموقَّع على نوعَين من البيانات التي نحتاجهما: عنوان البريد الإلكتروني الذي تم إثبات ملكيته، والقيمة الفريدة للمعرّف (المتوفّرة في الحقل sub
، للمشترك والحقل العادي).
يؤدي هذا إلى إكمال الخطوة 3.
6- ملخّص
نشرت تطبيق ويب App Engine. في الخطوة 1، حظرت الوصول إلى التطبيق على المستخدمين الذين اخترتهم فقط. في الخطوة 2، استعدت وعرضت هوية المستخدمين الذين سمحت لهم عمليات الشراء داخل التطبيق بالوصول إلى تطبيقك، ولاحظت كيف يمكن انتحال هذه المعلومات في حال إيقاف الشراء داخل التطبيق أو تجاوزه. في الخطوة 3، تحققت من تأكيدات هوية المستخدم الموقّعة بطريقة مشفّرة والتي لا يمكن انتحالها.
7. تنظيف
إنّ موارد Google Cloud Platform الوحيدة التي استخدمتها في هذا الدرس التطبيقي هي مثيلات App Engine فقط. وفي كل مرة نشرت فيها التطبيق، يتم إنشاء إصدار جديد وسيظل متوفرًا إلى أن يتم حذفه. اخرج من التمرين المعملي لحذف المشروع وجميع الموارد المضمنة فيه.