مهاجرت از سرویس کاربران App Engine به پلتفرم Cloud Identity (ماژول 21)

1. بررسی اجمالی

مجموعه کدهای ایستگاه انتقال بدون سرور (آموزش‌های عملی) و ویدیوهای مرتبط با هدف کمک به توسعه‌دهندگان بدون سرور Google Cloud برای مدرن کردن برنامه‌های خود با هدایت آنها از طریق یک یا چند انتقال، عمدتاً از سرویس‌های قدیمی دور می‌شوند. انجام این کار برنامه های شما را قابل حمل تر می کند و گزینه ها و انعطاف پذیری بیشتری در اختیار شما قرار می دهد و به شما امکان می دهد با طیف وسیع تری از محصولات Cloud ادغام شده و به آنها دسترسی داشته باشید و راحت تر به نسخه های زبان جدیدتر ارتقا دهید. در حالی که در ابتدا بر روی اولین کاربران Cloud، عمدتاً توسعه دهندگان App Engine (محیط استاندارد) تمرکز می شود، این مجموعه به اندازه کافی گسترده است که شامل سایر پلتفرم های بدون سرور مانند Cloud Functions و Cloud Run یا در صورت وجود جاهای دیگر است.

هدف از این کد لبه این است که به توسعه دهندگان موتور برنامه پایتون 2 نشان دهد که چگونه از API/سرویس کاربران App Engine به پلتفرم هویت ابری (GCIP) مهاجرت کنند. همچنین یک انتقال ضمنی از App Engine NDB به Cloud NDB برای دسترسی به Datastore (که عمدتاً در ماژول Migration 2 پوشش داده شده است) و همچنین ارتقاء به Python 3 وجود دارد.

ماژول 20 نحوه افزودن استفاده از Users API را به برنامه نمونه ماژول 1 پوشش می دهد. در این ماژول، برنامه ماژول 20 تمام شده را می گیرید و استفاده از آن را به پلتفرم Cloud Identity منتقل می کنید.

شما یاد خواهید گرفت که چگونه

  • استفاده از سرویس کاربران App Engine را با پلتفرم Cloud Identity جایگزین کنید
  • استفاده از App Engine NDB را با Cloud NDB جایگزین کنید (همچنین به ماژول 2 مراجعه کنید)
  • با استفاده از Firebase Auth ارائه دهندگان هویت احراز هویت مختلف را راه اندازی کنید
  • از Cloud Resource Manager API برای دریافت اطلاعات پروژه IAM استفاده کنید
  • از Firebase Admin SDK برای دریافت اطلاعات کاربر استفاده کنید
  • نمونه برنامه را به پایتون 3 پورت کنید

آنچه شما نیاز دارید

نظرسنجی

چگونه از این آموزش استفاده خواهید کرد؟

فقط آن را بخوانید آن را بخوانید و تمرینات را کامل کنید

تجربه خود را با پایتون چگونه ارزیابی می کنید؟

تازه کار متوسط مسلط

تجربه خود را در استفاده از خدمات Google Cloud چگونه ارزیابی می کنید؟

تازه کار متوسط مسلط

2. پس زمینه

سرویس App Engine Users یک سیستم احراز هویت کاربر برای استفاده توسط برنامه های App Engine است. Google Sign-In را به عنوان ارائه‌دهنده هویت خود ارائه می‌کند، پیوندهای ورود و خروج راحت را برای استفاده در برنامه‌ها فراهم می‌کند، و از مفهوم کاربران سرپرست و عملکرد فقط سرپرست پشتیبانی می‌کند. برای بهبود قابلیت حمل برنامه، Google Cloud توصیه می‌کند که از سرویس‌های همراه قدیمی App Engine به سرویس‌های مستقل Cloud ، به عنوان مثال، از سرویس کاربران به پلتفرم Cloud Identity ، مهاجرت کنید.

Identity Platform مبتنی بر احراز هویت Firebase است و تعدادی ویژگی سازمانی از جمله احراز هویت چند عاملی، پشتیبانی OIDC و SAML SSO، چند اجاره‌ای، 99.95% SLA و موارد دیگر را اضافه می‌کند. این تفاوت ها همچنین در صفحه مقایسه محصول Identity Platform و Firebase Authentication برجسته شده است. هر دو محصول به طور قابل توجهی ویژگی های بیشتری نسبت به عملکرد ارائه شده توسط سرویس کاربران دارند.

این آزمایشگاه کد ماژول 21 تغییر احراز هویت کاربر برنامه را از سرویس کاربران به ویژگی‌های پلتفرم هویت نشان می‌دهد که عملکرد نشان‌داده‌شده در ماژول 20 را به بهترین شکل منعکس می‌کند. .

در حالی که کد ماژول 20 به عنوان یک برنامه نمونه Python 2 "تبلیغ می شود"، خود منبع با Python 2 و 3 سازگار است و حتی پس از مهاجرت به Identity Platform (و Cloud NDB) در اینجا در ماژول 21، به همین شکل باقی می ماند. به استفاده از سرویس کاربران در حین ارتقا به پایتون 3 ادامه دهید زیرا مهاجرت به پلتفرم هویت اختیاری است. برای یادگیری نحوه ادامه استفاده از سرویس‌های همراه در حین ارتقا به زمان‌های اجرا به نسل دوم مانند پایتون 3، به آزمایشگاه کد و ویدیوی ماژول 17 مراجعه کنید.

این آموزش شامل مراحل زیر است:

  1. راه اندازی/پیش کار
  2. پیکربندی را به روز کنید
  3. کد برنامه را تغییر دهید

3. راه اندازی/پیش کار

این بخش توضیح می دهد که چگونه:

  1. پروژه Cloud خود را راه اندازی کنید
  2. دریافت نمونه برنامه پایه
  3. (دوباره) استقرار و تأیید اعتبار برنامه پایه
  4. خدمات/APIهای جدید Google Cloud را فعال کنید

این مراحل تضمین می‌کند که شما با کد کاری شروع می‌کنید که آماده انتقال به سرویس‌های Cloud مستقل است.

1. پروژه راه اندازی

اگر ماژول 20 را تکمیل کردید، از همان پروژه (و کد) دوباره استفاده کنید. از طرف دیگر، یک پروژه کاملاً جدید ایجاد کنید یا از پروژه موجود دیگری استفاده مجدد کنید. مطمئن شوید که پروژه دارای یک حساب صورتحساب فعال و یک برنامه App Engine فعال است. شناسه پروژه خود را بیابید و آن را در این برنامه کد در دسترس داشته باشید و هر زمان که با متغیر PROJ_ID روبرو شدید از آن استفاده کنید.

2. برنامه نمونه پایه را دریافت کنید

یکی از پیش نیازها، یک اپلیکیشن موتور اپلیکیشن ماژول 20 است، بنابراین یا لبه کد آن را کامل کنید (توصیه می شود؛ پیوند بالا) یا کد ماژول 20 را از مخزن کپی کنید. چه از مال خود استفاده کنید و چه ما، از اینجا شروع می کنیم ("START"). این لبه کد شما را در مسیر مهاجرت راهنمایی می کند و با کدی که شبیه آنچه در پوشه مخزن ماژول 21 است ("FINISH") به پایان می رسد.

پوشه Module 20 repo را کپی کنید. باید مانند خروجی زیر باشد، و ممکن است یک پوشه lib داشته باشد، اگر از ماژول 20 کد لبه استفاده کرده باشید:

$ ls
README.md               appengine_config.py     templates
app.yaml                main.py                 requirements.txt

3. (دوباره) استقرار و تأیید اعتبار برنامه پایه

مراحل زیر را برای استقرار برنامه Module 20 انجام دهید:

  1. در صورت وجود پوشه lib حذف کنید و pip install -t lib -r requirements.txt اجرا کنید تا دوباره پر شود. اگر پایتون 2 و 3 را نصب کرده اید، ممکن است نیاز به استفاده از pip2 داشته باشید.
  2. مطمئن شوید که ابزار خط فرمان gcloud را نصب و راه اندازی کرده اید و استفاده از آن را بررسی کرده اید.
  3. اگر نمی‌خواهید با هر دستور gcloud صادر شده PROJ_ID خود را وارد کنید، ابتدا پروژه Cloud را با gcloud config set project PROJ_ID تنظیم کنید.
  4. برنامه نمونه را با gcloud app deploy اجرا کنید
  5. تأیید کنید که برنامه همانطور که انتظار می رود بدون خطا اجرا شود. اگر ماژول 20 را تکمیل کرده باشید، برنامه اطلاعات ورود کاربر (ایمیل کاربر، "نشان مدیر" احتمالی، و دکمه ورود/خروج) را به همراه آخرین بازدیدها (در تصویر زیر) در بالا نمایش می دهد.

907e64c19ef964f8.png

ورود به سیستم به عنوان یک کاربر معمولی باعث می شود آدرس ایمیل کاربر نمایش داده شود و دکمه "ورود" به دکمه "خروج" تغییر می کند:

ad7b59916b69a035.png

ورود به سیستم به عنوان کاربر مدیر باعث می شود آدرس ایمیل کاربر همراه با "(admin)" در کنار آن نمایش داده شود:

867bcb3334149e4.png

4. API ها/سرویس های جدید Google Cloud را فعال کنید

مقدمه

برنامه Module 20 از App Engine NDB و Users API استفاده می‌کند، سرویس‌های همراهی که نیازی به راه‌اندازی اضافی ندارند، اما سرویس‌های Cloud مستقل این کار را انجام می‌دهند، و برنامه به‌روزرسانی شده از پلتفرم Cloud Identity و Cloud Datastore (از طریق کتابخانه سرویس گیرنده Cloud NDB ) استفاده می‌کند. . علاوه بر این، نیاز ما به تعیین کاربران مدیر App Engine نیز نیازمند استفاده از Cloud Resource Manager API است.

هزینه

  • App Engine و Cloud Datastore دارای سهمیه‌های ردیف «همیشه رایگان» هستند، و تا زمانی که زیر این محدودیت‌ها بمانید، نباید برای تکمیل این آموزش هزینه‌ای متحمل شوید. همچنین برای جزئیات بیشتر به صفحه قیمت گذاری App Engine و صفحه قیمت گذاری Cloud Datastore مراجعه کنید.
  • استفاده از پلتفرم Cloud Identity بسته به تعداد کاربران فعال ماهانه (MAU) یا تأییدهای احراز هویت صورت‌حساب می‌شود. برخی از نسخه های "رایگان" برای هر مدل استفاده در دسترس است. برای جزئیات بیشتر به صفحه قیمت آن مراجعه کنید. علاوه بر این، در حالی که App Engine و Cloud Datastore به صورت‌حساب نیاز دارند، استفاده از GCIP به خودی خود نیازی به فعال کردن صورت‌حساب ندارد تا زمانی که از سهمیه روزانه بدون ابزار آن تجاوز نکنید، بنابراین این را برای پروژه‌های Cloud که شامل Cloud مورد نیاز صورت‌حساب نیستند در نظر بگیرید. API ها/سرویس ها
  • استفاده از Cloud Resource Manager API در اکثر موارد در صفحه قیمت آن رایگان است.

کاربران بسته به ترجیح شما، APIهای Cloud را از کنسول Cloud یا از خط فرمان (از طریق دستور gcloud ، بخشی از Cloud SDK ) فعال می‌کنند. بیایید با Cloud Datastore و Cloud Resource Manager API شروع کنیم.

از کنسول Cloud

به صفحه کتابخانه مدیر API (برای پروژه صحیح) در Cloud Console بروید و با استفاده از نوار جستجو یک API را جستجو کنید. c7a740304e9d35b.png

این API ها را فعال کنید:

دکمه Enable را برای هر API به طور جداگانه پیدا کنید و روی آن کلیک کنید—ممکن است اطلاعات صورتحساب از شما خواسته شود. به عنوان مثال، صفحه مربوط به Resource Manager API در اینجا آمده است:

fc7bd8f4c49d12e5.png

دکمه پس از فعال شدن (به طور کلی پس از چند ثانیه) به مدیریت تغییر می کند:

8eca12d6cc7b45b0.png

Cloud Datastore را به همین روش فعال کنید:

83811599b110e46b.png

از خط فرمان

در حالی که فعال کردن API ها از کنسول از نظر بصری آموزنده است، برخی خط فرمان را ترجیح می دهند. شما این امتیاز اضافه را دریافت می کنید که می توانید هر تعداد API را به طور همزمان فعال کنید. این دستور را برای فعال کردن APIهای Cloud Datastore و 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" برای هر API استفاده شده در دستور بالا، نام سرویس API نامیده می شود و آنها را می توان در پایین صفحه کتابخانه برای هر API یافت. اگر می‌خواهید سایر APIهای Cloud را برای برنامه‌های خود فعال کنید، می‌توانید نام سرویس مربوطه آنها را در صفحات API مربوطه آنها پیدا کنید. این دستور همه نام‌های سرویس APIهایی را که می‌توانید فعال کنید فهرست می‌کند:

gcloud services list --available --filter="name:googleapis.com" .

چه در کنسول Cloud یا در خط فرمان، پس از تکمیل مراحل بالا، نمونه ما اکنون می‌تواند به آن APIها دسترسی داشته باشد. مراحل بعدی فعال کردن پلتفرم Cloud Identity و ایجاد تغییرات کد لازم است.

فعال کردن و راه‌اندازی Cloud Identity Platform (فقط کنسول Cloud)

Cloud Identity Platform یک سرویس Marketplace است زیرا به منبعی خارج از Google Cloud متصل می شود یا به آن وابسته است، به عنوان مثال، Firebase Authentication . در حال حاضر، فقط می‌توانید خدمات Marketplace را از کنسول Cloud فعال کنید. مراحل زیر را دنبال کنید:

  1. به صفحه Cloud Identity Platform در Cloud Marketplace بروید و روی دکمه Enable در آنجا کلیک کنید. در صورت درخواست از Firebase Authentication ارتقا دهید—با انجام این کار، قفل ویژگی‌های اضافی مانند مواردی که قبلا در بخش پس‌زمینه توضیح داده شد، باز می‌شود. در اینجا صفحه بازار است که دکمه فعال کردن را برجسته می کند: 28475f1c9b29de69.png
  2. پس از فعال شدن Identity Platform، ممکن است به طور خودکار به صفحه Identity Providers منتقل شوید. اگر نه، از این لینک مناسب برای رسیدن به آنجا استفاده کنید. fc2d92d42a5d1dd7.png
  3. ارائه دهنده Google Auth را فعال کنید. اگر هیچ ارائه‌دهنده‌ای راه‌اندازی نشده است، روی افزودن یک ارائه‌دهنده کلیک کنید و Google را انتخاب کنید. وقتی به این صفحه بازگردید، ورودی Google باید فعال باشد. Google تنها ارائه‌دهنده تأییدیه است که ما در این آموزش استفاده می‌کنیم تا سرویس کاربران App Engine را به عنوان یک سرویس ورود به سیستم Google سبک وزن نشان دهیم. در برنامه‌های خودتان، می‌توانید ارائه‌دهندگان تأیید اعتبار اضافی را فعال کنید.
  4. هنگامی که Google و سایر ارائه دهندگان تأیید اعتبار مورد نظر را انتخاب و راه اندازی کردید، روی Application Setup Details کلیک کنید و از پنجره محاوره ای مطمئن، apiKey و authDomain را در شیء config در تب Web کپی کنید و هر دو را در جایی امن ذخیره کنید. چرا همه آن را کپی نمی کنید؟ قطعه موجود در این گفتگو دارای کد سخت و دارای تاریخ است، بنابراین فقط مهم‌ترین بیت‌ها را ذخیره کنید و با استفاده همزمان‌تر از Firebase Auth از آنها در کد خود استفاده کنید. هنگامی که مقادیر را کپی کردید و آنها را در مکانی امن ذخیره کردید، روی دکمه Close کلیک کنید و تمام تنظیمات لازم را تکمیل کنید. bbb09dcdd9be538e.png

4. پیکربندی را به روز کنید

به‌روزرسانی‌های پیکربندی شامل تغییر فایل‌های پیکربندی مختلف و همچنین ایجاد معادل App Engine اما در اکوسیستم Cloud Identity Platform است.

appengine_config.py

  • در صورت ارتقا به پایتون 3، appengine_config.py حذف کنید
  • اگر قصد دارید به پلتفرم Identity مدرن بسازید اما روی پایتون 2 بمانید ، فایل را حذف نکنید. در عوض، ما آن را بعداً در طول بکپورت پایتون 2 به روز خواهیم کرد.

الزامات. txt

فایل requirements.txt ماژول 20 فقط فلاسک فهرست شده است. برای ماژول 21، بسته های زیر را اضافه کنید:

محتویات requirements.txt اکنون باید به شکل زیر باشد:

flask
google-auth
google-cloud-ndb
google-cloud-resource-manager
firebase-admin

app.yaml

  • ارتقاء به پایتون 3 به معنای ساده کردن فایل app.yaml است. همه چیز را به جز دستور زمان اجرا حذف کنید و آن را روی نسخه ای از پایتون 3 تنظیم کنید که در حال حاضر پشتیبانی می شود. نمونه در حال حاضر از نسخه 3.10 استفاده می کند.
  • اگر با پایتون 2 می‌مانید، هنوز هیچ اقدامی در اینجا انجام ندهید.

قبل از:

runtime: python27
threadsafe: yes
api_version: 1

handlers:
- url: /.*
  script: main.app

برنامه نمونه ماژول 20 کنترل کننده فایل ایستا ندارد. اگر برنامه های شما این کار را می کنند، آنها را دست نخورده بگذارید. در صورت تمایل می‌توانید همه کنترل‌کننده‌های اسکریپت خود را حذف کنید یا فقط تا زمانی که دسته‌های آن‌ها را به auto تغییر دهید، آنها را برای مرجع رها کنید، همانطور که در راهنمای مهاجرت app.yaml توضیح داده شده است. با این تغییرات، app.yaml به روز شده برای Python 3 ساده شده است:

بعد از:

runtime: python310

سایر به روز رسانی های پیکربندی

چه در پایتون 2 بمانید و چه در حال انتقال به پایتون 3، اگر پوشه lib دارید، آن را حذف کنید.

5. کد برنامه را تغییر دهید

این بخش به‌روزرسانی‌های فایل برنامه اصلی، main.py ارائه می‌کند که جایگزین استفاده از سرویس کاربران App Engine با پلتفرم Cloud Identity است. پس از به‌روزرسانی برنامه اصلی، الگوی وب، templates/index.html را به‌روزرسانی خواهید کرد.

به روز رسانی واردات و مقداردهی اولیه

برای به روز رسانی واردات و مقداردهی اولیه منابع برنامه، مراحل زیر را دنبال کنید:

  1. برای واردات، App Engine NDB را با Cloud NDB جایگزین کنید.
  2. همراه با Cloud NDB، Cloud Resource Manager را نیز وارد کنید.
  3. Identity Platform مبتنی بر Firebase Auth است، بنابراین Firebase Admin SDK را وارد کنید.
  4. Cloud API نیاز به استفاده از یک سرویس گیرنده API دارد، بنابراین آن را برای 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 Admin

دو جزء برای اضافه کردن به برنامه وجود دارد که از شناسایی کاربران ادمین پشتیبانی می کند:

  • _get_gae_admins() - مجموعه ای از کاربران مدیر را جمع آوری می کند. یک بار تماس گرفت و ذخیره کرد
  • is_admin() - بررسی می کند که آیا کاربر وارد شده یک کاربر ادمین است یا خیر. با ورود به هر کاربری تماس گرفت

تابع ابزار، _get_gae_admins() ، API مدیر منابع را فراخوانی می‌کند تا سیاست مجوز فعلی Cloud IAM را واکشی کند. خط مشی اجازه تعیین و اجرا می کند که چه نقش هایی به کدام یک از مدیران اعطا می شود (کاربران انسانی، حساب های خدمات و غیره). راه اندازی شامل:

  • واکشی شناسه پروژه Cloud ( PROJ_ID )
  • ایجاد یک مشتری API مدیر منابع ( rm_client )
  • ایجاد مجموعه ای (فقط خواندنی) از نقش های مدیر App Engine ( _TARGETS )

Resource Manager به شناسه پروژه Cloud نیاز دارد، بنابراین google.auth.default() را وارد کرده و آن تابع را برای دریافت شناسه پروژه فراخوانی کنید. این تماس دارای پارامتری است که شبیه یک URL است اما یک محدوده مجوز OAuth2 است. هنگام اجرای برنامه‌ها در فضای ابری، به‌عنوان مثال، در برنامه Compute Engine VM یا App Engine، یک حساب سرویس پیش‌فرض ارائه می‌شود که دارای امتیازات گسترده است. با رعایت بهترین روش کمترین امتیاز، توصیه می کنیم حساب های خدمات مدیریت شده توسط کاربر خود را ایجاد کنید.

برای تماس‌های API، بهتر است دامنه برنامه‌های خود را به حداقل سطح مورد نیاز برای عملکرد صحیح کاهش دهید. فراخوانی Resource Manager API که ما انجام خواهیم داد 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() زیر را دقیقاً در زیر نمونه‌سازی کلاینت Cloud NDB API ( ds_client ) به main.py اضافه کنید:

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

هنگامی که کاربران وارد برنامه می شوند، موارد زیر رخ می دهد:

  1. پس از ورود کاربر به Firebase، یک بررسی سریع از قالب وب انجام می شود.
  2. هنگامی که وضعیت auth در قالب تغییر می کند، یک فراخوانی fetch() به سبک Ajax با /is_admin که تابع بعدی، is_admin() است، گرفته می شود.
  3. توکن ID Firebase در بدنه POST به is_admin() ارسال می‌شود، که آن را از هدرها خارج می‌کند و Firebase Admin SDK را برای تأیید اعتبار فراخوانی می‌کند. اگر کاربر معتبری است، آدرس ایمیل او را استخراج کنید و بررسی کنید که آیا کاربر مدیر است یا خیر.
  4. سپس نتیجه Boolean به عنوان یک 200 موفق به الگو برگردانده می شود.

فقط بعد از _get_gae_admins() is_admin() به main.py اضافه کنید:

@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 وابسته نیست، به این معنی که می توانید برنامه های خود را به Cloud Run یا سایر سرویس ها منتقل کنید. علاوه بر این، می‌توانید تنها با جابه‌جایی به نقش‌های مورد نظر در _TARGETS ، تعریف «کاربر مدیر» را برای برنامه‌های خود تغییر دهید، در حالی که سرویس کاربران برای نقش‌های مدیر App Engine کدگذاری شده است.

Firebase Auth را راه اندازی کنید و کاربران مدیر App Engine را ذخیره کنید

می‌توانستیم Firebase Auth را در بالا، نزدیک به همان نقطه‌ای که برنامه 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 تغییر نمی کند. دسترسی به Datastore مستلزم استفاده صریح از مدیر زمینه کلاینت Cloud NDB API، ds_client.context() . در کد، این بدان معناست که تماس‌های Datastore را هم در store_visit() و هم fetch_visits() داخل پایتون 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 Auth و Cloud Identity Platform عمدتاً سمت مشتری هستند. در نتیجه، بیشتر کد مدیریت کاربر در برنامه ماژول 20 به قالب وب ماژول 21 منتقل می شود.

در main.py ، زمینه وب پنج قطعه داده ضروری را به الگو ارسال می‌کند، چهار مورد اول فهرست شده به مدیریت کاربر مرتبط هستند و بسته به اینکه کاربر وارد شده است یا خیر، متفاوت است:

  • who - ایمیل کاربر در صورت ورود به سیستم یا کاربر در غیر این صورت
  • admin - اگر کاربر وارد شده یک مدیر باشد، نشان (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)

تمام مدیریت کاربر در حال انتقال به الگوی وب است، بنابراین فقط بازدیدها باقی می‌ماند و کنترل‌کننده اصلی را به آنچه در برنامه ماژول 1 داشتیم برمی‌گرداند:

بعد از:

@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 Auth در حال اجرا در قالب و یک پورت جزئی از همه آن کدهایی که به جاوا اسکریپت منتقل کردیم. ما شاهد بودیم که 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 وجود دارد، بنابراین بیایید آنها را تکه تکه کنیم.

واردات فایربیس

در حالی که هنوز در هدر سند HTML هستید، پس از گذشتن از عنوان صفحه، اجزای Firebase مورد نیاز را وارد کنید. اکنون اجزای Firebase برای کارایی به چندین ماژول تقسیم می شوند. کد اولیه Firebase از ماژول اصلی برنامه Firebase وارد می‌شود، در حالی که توابعی که Firebase auth، Google به‌عنوان ارائه‌دهنده احراز هویت، ورود و خروج، و تغییر وضعیت احراز هویت «بازگشت» را مدیریت می‌کنند، همگی از ماژول Firebase Auth وارد می‌شوند:

<!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 در جلسه مرورگر شما ثبت شده باشد. به عبارت دیگر، هنگامی که چندین حساب دارید، همانطور که انتظار می رود با این "انتخاب کننده حساب" روبرو می شوید: a38369389b7c4c7e.png با این حال، اگر تنها یک کاربر در جلسه وجود داشته باشد، فرآیند ورود به سیستم به طور خودکار بدون هیچ گونه تعامل کاربر تکمیل می شود. (پنجره ظاهر می‌شود و سپس ناپدید می‌شود.) می‌توانید با لغو نظر خط پارامتر سفارشی، کادر گفتگوی انتخابگر حساب را برای یک کاربر (در مقابل ورود فوری به برنامه) مجبور کنید. در صورت فعال بودن، حتی ورود به سیستم یک کاربره، انتخابگر حساب را نشان می دهد: b75624cb68d94557.png

توابع ورود و خروج

خطوط بعدی کد عملکردهایی را برای کلیک روی دکمه ورود یا خروج تشکیل می دهند:

// 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 دارد و اقدامات زیر را انجام می‌دهد:

  1. آدرس ایمیل کاربر برای نمایش تنظیم شده است.
  2. دکمه ورود به خروج تغییر می کند.
  3. یک فراخوانی به سبک Ajax به /is_admin برای تعیین اینکه آیا نشان کاربر مدیر (admin) نشان داده می شود یا خیر، انجام می شود.

هنگامی که کاربر از سیستم خارج می شود، عبارت else برای بازنشانی تمام اطلاعات کاربر اجرا می شود:

  1. نام کاربری روی کاربر تنظیم شد
  2. هر نشان مدیر حذف شد
  3. دکمه خروج دوباره به ورود تغییر کرد

متغیرهای قالب

پس از پایان بخش هدر، بدنه اصلی با متغیرهای قالب شروع می شود که با عناصر HTML جایگزین می شوند که در صورت لزوم تغییر می کنند:

  1. نام کاربری نمایش داده شده
  2. (admin) نشان مدیر (در صورت وجود)
  3. دکمه ورود یا خروج
<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>

این تغییرات مورد نیاز در برنامه و قالب وب برای تغییر از App Engine NDB و Users API به Cloud NDB و Identity Platform و همچنین ارتقا به Python 3 را به پایان می‌رساند. برای ورود به برنامه نمونه جدید ماژول 21 تبریک می‌گوییم! نسخه ما برای بررسی در پوشه Repo Module 21b موجود است.

بخش بعدی کدلاب اختیاری است (*) و فقط برای کاربرانی که برنامه‌هایشان باید در پایتون 2 باقی بماند، شما را طی مراحل لازم برای رسیدن به برنامه ماژول 21 پایتون 2 راهنمایی می‌کند.

6. *بکپورت پایتون 2

این بخش اختیاری برای توسعه دهندگانی است که مهاجرت پلتفرم هویت را انجام می دهند اما باید در زمان اجرا پایتون 2 به اجرا ادامه دهند. اگر این موضوع برای شما نگران کننده نیست، از این بخش صرفنظر کنید.

برای ایجاد یک نسخه کاربردی Python 2 از برنامه Module 21، به موارد زیر نیاز دارید:

  1. الزامات زمان اجرا : فایل‌های پیکربندی که از پایتون 2 پشتیبانی می‌کنند و تغییرات مورد نیاز در برنامه اصلی برای جلوگیری از ناسازگاری پایتون 3
  2. تغییر جزئی کتابخانه: پایتون 2 قبل از افزودن برخی ویژگی‌های مورد نیاز به کتابخانه مشتری Resource Manager منسوخ شد. در نتیجه، شما به یک راه جایگزین برای دسترسی به آن عملکرد از دست رفته نیاز دارید.

بیایید این مراحل را اکنون انجام دهیم و با پیکربندی شروع کنیم.

appengine_config.py را بازیابی کنید

قبلاً در این آموزش، به شما راهنمایی شد که appengine_config.py حذف کنید، زیرا توسط موتور اجرای برنامه Python 3 استفاده نمی شود. برای پایتون 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

الزامات. txt

برای ماژول 21، Google Auth ، Cloud NDB ، Cloud Resource Manager و Firebase Admin SDK را به Python 3 requirements.txt اضافه کردیم. وضعیت پایتون 2 پیچیده تر است:

  • Resource Manager API عملکرد خط مشی مجاز مورد نیاز برای برنامه نمونه را فراهم می کند. متأسفانه این پشتیبانی هنوز در نسخه نهایی Python 2 کتابخانه مشتری Cloud Resource Manager در دسترس نبود. (فقط در نسخه پایتون 3 موجود است.)
  • در نتیجه، یک راه جایگزین برای دسترسی به این ویژگی از API مورد نیاز است. راه حل این است که از کتابخانه سرویس گیرنده Google APIs سطح پایین برای برقراری ارتباط با API استفاده کنید. برای تغییر به این کتابخانه مشتری، google-cloud-resource-manager را با بسته سطح پایین google-api-python-client جایگزین کنید.
  • از آنجایی که پایتون 2 غروب شده است ، نمودار وابستگی که از ماژول 21 پشتیبانی می کند، نیاز به قفل کردن بسته های خاصی در نسخه های خاص دارد. برخی از بسته ها باید فراخوانی شوند حتی اگر در برنامه Python 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

اگر هر دو پایتون 2 و 3 را روی سیستم توسعه خود نصب کرده اید، ممکن است لازم باشد به جای pip از pip2 استفاده کنید.

کد برنامه را تغییر دهید

خوشبختانه اکثر تغییرات مورد نیاز در فایل های پیکربندی است. تنها تغییر مورد نیاز در کد برنامه، یک به‌روزرسانی جزئی برای استفاده از کتابخانه سرویس گیرنده Google API سطح پایین به جای کتابخانه مشتری Resource Manager برای دسترسی به API است. برای الگوی وب 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 Admin

چند تغییر در _get_gae_admins() برای پشتیبانی از استفاده از کتابخانه سرویس گیرنده سطح پایین مورد نیاز است. بیایید ابتدا در مورد آنچه در حال تغییر است بحث کنیم سپس همه کدها را برای به روز رسانی در اختیار شما قرار دهیم.

کد پایتون 2 نیاز به استفاده از اعتبارنامه و شناسه پروژه بازگشتی از google.auth.default() دارد. اعتبارنامه ها در پایتون 3 استفاده نمی شوند، بنابراین به یک متغیر ساختگی زیرخط عمومی ( _ ) اختصاص داده شد. از آنجایی که برای نسخه Python 2 مورد نیاز است، زیرخط را به CREDS تغییر دهید. همچنین، به جای ایجاد یک مشتری API مدیر منابع، یک نقطه پایانی سرویس API ایجاد خواهید کرد که از نظر مفهومی شبیه به یک کلاینت API است، بنابراین نام متغیر یکسانی ( 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)

تفاوت دیگر این است که کتابخانه مشتری Resource Manager اشیاء سیاست اجازه را برمی گرداند که از نشانه گذاری مشخصه نقطه دار استفاده می کنند در حالی که کتابخانه سرویس گیرنده سطح پایین دیکشنری های پایتون را برمی گرداند که در آن از براکت های مربع ( [ ] ) استفاده می شود، به عنوان مثال، از binding.role برای کتابخانه مشتری Resource Manager در مقابل binding['role'] برای کتابخانه سطح پایین. اولی همچنین از نام‌های «underscore_separated» در مقابل کتابخانه سطح پایین‌تر استفاده می‌کند که نام‌های «CamelCased» را ترجیح می‌دهد به‌علاوه یک روش کمی متفاوت برای ارسال در پارامترهای API.

این تفاوت های استفاده در زیر نشان داده شده است:

قبل از:

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() که قبلاً به روز شده است متکی است.

با این کار تغییرات لازم برای بکپورت کردن برنامه ماژول 21 پایتون 3 به پایتون 2 به پایان می رسد. برای ورود به برنامه نمونه به روز شده ماژول 21 تبریک می گویم! همه کدها را در پوشه Module 21a repo پیدا خواهید کرد.

7. خلاصه/پاکسازی

آخرین اقدامات در CodeLab این است که اطمینان حاصل شود که اصولگرایان (کاربران یا حساب های خدمات) در حال اجرا این برنامه دارای مجوزهای مناسب برای انجام این کار هستند ، سپس برنامه خود را برای تأیید آن به صورت مورد نظر مستقر کنید و تغییرات در خروجی منعکس شود.

امکان خواندن IAM اجازه سیاست

پیش از این ، ما شما را با چهار نقش مورد نیاز برای شناسایی به عنوان کاربر App Engine Admin معرفی کردیم ، اما اکنون یک پنجم وجود دارد که با آن آشنا شوید:

  • roles/viewer
  • roles/editor
  • roles/owner
  • roles/appengine.appAdmin
  • roles/resourcemanager.projectIamAdmin (برای اصولگرایان دسترسی به IAM اجازه سیاست)

roles/resourcemanager.projectIamAdmin به اصول اولیه این امکان را می دهد تا مشخص کنند که آیا یک کاربر نهایی عضو هر یک از نقش های مدیر موتور برنامه است. بدون عضویت در roles/resourcemanager.projectIamAdmin ، تماس با مدیر منابع ابری 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 شناسه پروژه ابری و USR_MGD_SVC_ACCT@PROJ_ID.iam.gserviceaccount.com حساب خدمات مدیریت شده توسط کاربر است که برای برنامه خود ایجاد می کنید. این دستور خط مشی IAM را برای پروژه خود در نظر می گیرد که در آن می توانید تأیید کنید که حساب خدمات دارای عضویت در roles/resourcemanager.projectIamAdmin . برای اطلاعات بیشتر، به مستندات مرجع مراجعه کنید. برای تکرار ، نیازی به صدور آن دستور در این CodeLab نیست ، اما این را به عنوان مرجع برای نوسازی برنامه های خود ذخیره کنید.

استقرار و تأیید برنامه

برنامه خود را با دستور استاندارد gcloud app deploy در ابر بارگذاری کنید. پس از استقرار ، باید عملکردی تقریباً یکسان با برنامه ماژول 20 مشاهده کنید به جز این که سرویس کاربران موتور برنامه را با پلت فرم هویت Cloud (و Firebase Auth) برای مدیریت کاربر جایگزین کرده اید:

3A83AE745121D70.PNG

یکی از تفاوت هایی که در مقایسه با ماژول 20 مشاهده خواهید کرد این است که کلیک بر روی ورود به سیستم به جای تغییر مسیر ، در برخی از تصاویر زیر ضبط شده است. با این حال ، مانند ماژول 20 ، این رفتار بسته به تعداد حساب های Google در مرورگر کمی متفاوت است.

اگر هیچ کاربر در مرورگر یا یک کاربر واحد که هنوز وارد آن نشده اند ، ثبت نام نکرده است ، یک پنجره ورود به سیستم Google عمومی ارائه می شود:

8437F5F3D489A942.PNG

اگر یک کاربر واحد در مرورگر شما ثبت شده است اما در جای دیگر امضا می شود ، هیچ گفتگو ظاهر نمی شود (یا فوراً بسته می شود و بسته می شود) و برنامه به حالت امضا شده می رود (دکمه ایمیل و دکمه ورود به سیستم را نشان می دهد).

برخی از توسعه دهندگان ممکن است بخواهند یک حساب کاربری را حتی برای یک کاربر واحد ارائه دهند:

B75624CB68D94557.PNG

برای اجرای این کار ، provider.setCustomParameters({prompt: 'select_account'}); خط در الگوی وب همانطور که در ابتدا توضیح داده شد.

اگر چندین کاربر وجود داشته باشد ، گفتگوی حساب-پیکر ظاهر می شود (به تصویر زیر مراجعه کنید). در صورت عدم ورود به سیستم ، از کاربر خواسته می شود. اگر از قبل وارد سیستم شوید ، پنجره بازشو ناپدید می شود و برنامه به حالت امضا شده می رود.

C454455B6020D5E4.png

حالت امضا شده ماژول 21 با رابط کاربری ماژول 20 یکسان به نظر می رسد:

49ebe4dcc1eff1eff.png

در مورد زمانی که یک کاربر سرپرست وارد سیستم شده است ، همین مسئله نیز صادق است:

44302F35B39856EB.PNG

بر خلاف ماژول 21 ، ماژول 20 همیشه به منطق محتوای الگوی وب از برنامه (کد سمت سرور) دسترسی پیدا می کند. نقص ماژول 20 این است که وقتی یک کاربر نهایی برای اولین بار به برنامه برخورد می کند ، یک بازدید ثبت می شود و وقتی کاربر وارد سیستم می شود ، دیگری ثبت می شود.

برای ماژول 21 ، منطق ورود فقط در الگوی وب (کد سمت مشتری) صورت می گیرد. هیچ سفر لازم برای سمت سرور وجود ندارد تا تعیین کند که چه محتوا را نمایش می دهد. تنها تماس برقرار شده به سرور ، بررسی کاربران Admin پس از ورود به سیستم کاربر نهایی است. این بدان معنی است که ورود و ورود به سیستم بازدیدهای اضافی را ثبت نمی کند ، بنابراین جدیدترین لیست بازدیدها برای اقدامات مدیریت کاربر ثابت است. توجه کنید که تصاویر بالا همان مجموعه چهار بازدید را در چندین ورود به سیستم نمایش داده می کنند.

تصاویر ماژول 20 "اشکال دو بازدید" را در ابتدای این CodeLab نشان می دهد. ثبت های جداگانه برای هر اقدام ورود به سیستم یا ورود به سیستم نمایش داده می شود. جدول زمانی جدیدترین بازدید را برای هر تصویری که ترتیب زمانی را نشان می دهد ، بررسی کنید.

پاک کن

ژنرال

اگر در حال حاضر تمام شده اید ، توصیه می کنیم برنامه موتور برنامه خود را غیرفعال کنید تا از صدور صورتحساب خودداری کنید. اما اگر مایل به آزمایش یا آزمایش بیشتر هستید ، پلت فرم موتور برنامه سهمیه رایگان دارد ، و بنابراین تا زمانی که از آن ردیف استفاده تجاوز نکنید ، نباید از آن استفاده کنید. این برای محاسبه است ، اما ممکن است هزینه خدمات مربوط به موتور برنامه مربوطه نیز وجود داشته باشد ، بنابراین برای اطلاعات بیشتر صفحه قیمت گذاری آن را بررسی کنید. اگر این مهاجرت شامل سایر خدمات ابری باشد ، این موارد به طور جداگانه صورتحساب می شوند. در هر صورت ، در صورت کاربرد ، بخش "خاص این CodeLab" را در زیر مشاهده کنید.

برای افشای کامل ، استقرار در یک بستر محاسباتی بدون سرور Google Cloud مانند موتور برنامه هزینه های ساخت و ذخیره جزئی را متحمل می شود. Cloud Build سهمیه رایگان خود را مانند ذخیره سازی ابری دارد. ذخیره سازی آن تصویر از برخی از آن سهمیه استفاده می کند. با این حال ، شما ممکن است در منطقه ای زندگی کنید که چنین لایه ای رایگان نداشته باشد ، بنابراین از استفاده از ذخیره سازی خود آگاه باشید تا هزینه های احتمالی را به حداقل برسانید. "پوشه های" ذخیره سازی ابری خاص شما باید مرور کنید: شامل موارد زیر است:

  • 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 ".

از طرف دیگر ، اگر نمی خواهید با این برنامه یا سایر CodeLabs مهاجرت مرتبط ادامه دهید و می خواهید همه چیز را به طور کامل حذف کنید ، پروژه خود را خاموش کنید .

مخصوص این codeLab

خدمات ذکر شده در زیر منحصر به این CodeLab است. برای اطلاعات بیشتر به مستندات هر محصول مراجعه کنید:

  • سرویس Datastore Engine App توسط Cloud Datastore (Cloud Firestore در حالت Datastore) ارائه شده است که دارای یک ردیف رایگان نیز هست. برای اطلاعات بیشتر به صفحه قیمت گذاری آن مراجعه کنید.
  • استفاده از پلت فرم هویت ابری بسته به نوع خدمات خود که از آن استفاده می کنید ، دارای سطح "رایگان" است. برای اطلاعات بیشتر به صفحه قیمت گذاری آن مراجعه کنید.
  • استفاده از API Manager Cloud Resource Manager برای بیشتر قسمت در صفحه قیمت گذاری آن رایگان است.

مراحل بعدی

فراتر از این آموزش ، سایر ماژول های مهاجرت که بر دور شدن از خدمات بسته بندی شده میراث متمرکز شده اند ، شامل موارد زیر هستند:

  • ماژول 2 : از App Engine ndb به Cloud NDB مهاجرت کنید
  • ماژول های 7-9 : از صف کار App Engine (وظایف فشار) به کارهای ابری مهاجرت کنید
  • ماژول های 12-13 : از Memcache App Engine به Cloud MemoryStore مهاجرت کنید
  • ماژول های 15-16 : از Blobstore App Engine به ذخیره سازی ابری مهاجرت کنید
  • ماژول های 18-19 : مهاجرت از صف کار موتور برنامه (کارهای بکشید) به Cloud Pub/Sub

App Engine دیگر تنها پلت فرم بدون سرور در Google Cloud نیست. اگر یک برنامه موتور برنامه کوچک یا برنامه ای دارید که عملکرد محدودی دارد و مایل به تبدیل آن به یک میکروسرویس مستقل است ، یا می خواهید یک برنامه یکپارچه را به چند مؤلفه قابل استفاده مجدد تبدیل کنید ، این دلایل خوبی برای در نظر گرفتن حرکت به سمت توابع ابر است. اگر کانتینریزاسیون به بخشی از گردش کار توسعه برنامه شما تبدیل شده است ، به ویژه اگر از خط لوله CI/CD (ادغام مداوم/تحویل مداوم یا استقرار مداوم) تشکیل شود ، مهاجرت را به Cloud Run در نظر بگیرید. این سناریوها توسط ماژول های زیر پوشانده شده است:

  • از App Engine به توابع ابر مهاجرت کنید: به ماژول 11 مراجعه کنید
  • مهاجرت از موتور برنامه به ابر اجرا: به ماژول 4 مراجعه کنید تا برنامه خود را با Docker یا ماژول 5 کانتینر کنید تا این کار را بدون ظروف ، دانش Docker یا Dockerfile انجام دهید.

جابجایی به پلت فرم بدون سرور دیگر اختیاری است و توصیه می کنیم قبل از ایجاد هرگونه تغییر ، بهترین گزینه ها را برای برنامه های خود در نظر بگیرید و از موارد استفاده کنید.

صرف نظر از این که کدام ماژول مهاجرت را در نظر بگیرید ، تمام محتوای ایستگاه مهاجرت بدون سرور (CodeLabs ، فیلم ها ، کد منبع [در صورت وجود]) را می توان در منبع باز خود دسترسی پیدا کرد. README REPO همچنین راهنمایی هایی را در مورد مهاجرت ها و هرگونه "دستور" مربوط به ماژول های مهاجرت ارائه می دهد.

8. منابع اضافی

ذکر شده در زیر منابع اضافی برای توسعه دهندگان مورد کاوش در این ماژول های مهاجرت مربوطه است. در زیر ، می توانید بازخورد خود را در مورد این محتوا ارائه دهید ، پیوندهایی به کد پیدا کنید ، و بخش های مختلفی از مستندات را که ممکن است مفید باشد ، ارائه دهید.

مسائل مربوط به CodeLabs/بازخورد

اگر در مورد این CodeLab مشکلی پیدا کردید ، لطفاً قبل از تشکیل پرونده ، ابتدا موضوع خود را جستجو کنید. پیوندهایی برای جستجو و ایجاد موضوعات جدید:

منابع مهاجرت

پیوندها به پوشه های repo برای ماژول 20 (شروع) و ماژول 21 (پایان) را می توان در جدول زیر یافت.

Codelab

پایتون 2

پایتون 3

ماژول 20

کد

(n/a)

ماژول 21 (این CodeLab)

کد

کد

مراجع آنلاین

در زیر منابع مرتبط برای این آموزش وجود دارد:

پلت فرم هویت ابری و بازار ابر

مدیر منابع ابری ، Cloud IAM ، Admin SDK Admin Firebase

کاربران موتور برنامه ، موتور برنامه NDB ، Cloud NDB ، Cloud Datastore

سایر منابع ماژول مهاجرت

مهاجرت موتور برنامه

بسترهای نرم افزاری برنامه

ابر SDK

سایر اطلاعات ابر

ویدیوها

مجوز

این کار تحت مجوز عمومی Creative Commons Attribution 2.0 مجوز دارد.