Vom App Engine-Nutzerdienst zur Cloud Identity Platform migrieren (Modul 21)

1. Übersicht

Die Codelabs-Reihe zur Serverless Migration Station (zum Selbststudium, praxisorientierte Anleitungen) und ähnliche Videos sollen Entwickler von Google Cloud Serverless bei der Modernisierung ihrer Anwendungen unterstützen, indem sie eine oder mehrere Migrationen durchgehen, in erster Linie von Legacy-Diensten. Dadurch werden Ihre Anwendungen portabler und bieten mehr Optionen und Flexibilität, sodass Sie eine breitere Palette von Cloud-Produkten einbinden und darauf zugreifen sowie einfacher auf neuere Sprachversionen upgraden können. Der Schwerpunkt dieser Reihe liegt anfangs auf die ersten Cloud-Nutzer, in erster Linie auf Entwicklern von App Engine (Standardumgebung). Sie ist aber umfassend genug, um auch andere serverlose Plattformen wie Cloud Functions und Cloud Run oder gegebenenfalls andere Plattformen einzubeziehen.

In diesem Codelab erfahren Sie, wie App Engine-Entwickler für Python 2 von der App Engine Users API/-Anwendung zu Cloud Identity Platform (GCIP) migrieren. Außerdem gibt es eine implizite Migration von App Engine NDB zu Cloud NDB für den Datastore-Zugriff (hauptsächlich behandelt in Migrationsmodul 2) sowie ein Upgrade auf Python 3.

In Modul 20 wird beschrieben, wie Sie die Nutzer-API zur Beispiel-App für Modul 1 hinzufügen. In diesem Modul migrieren Sie die abgeschlossene Anwendung in Modul 20 zur Cloud Identity Platform.

Sie werden lernen,

  • Ersetzen Sie die Verwendung des App Engine-Nutzerdienstes durch die Cloud Identity Platform.
  • Ersetzen Sie die Verwendung von App Engine NDB durch Cloud NDB (siehe auch Modul 2).
  • Verschiedene Identitätsanbieter für die Authentifizierung mit Firebase Auth einrichten
  • Cloud Resource Manager API zum Abrufen von Projekt-IAM-Informationen verwenden
  • Mit dem Firebase Admin SDK Nutzerinformationen abrufen
  • Beispielanwendung nach Python 3 übertragen

Voraussetzungen

Umfrage

Wie möchten Sie diese Anleitung nutzen?

<ph type="x-smartling-placeholder"></ph> Lesen Sie sie nur durch. Lies sie dir durch und absolviere die Übungen

Wie würden Sie Ihre Erfahrung mit Python bewerten?

<ph type="x-smartling-placeholder"></ph> Neuling Mittel Kompetent

Wie würden Sie Ihre Erfahrungen im Umgang mit Google Cloud-Diensten bewerten?

<ph type="x-smartling-placeholder"></ph> Neuling Mittel Kompetent

2. Hintergrund

Der App Engine-Nutzerdienst ist ein Nutzerauthentifizierungssystem für App Engine-Anwendungen. Sie bietet Google Log-in als Identitätsanbieter, praktische An- und Abmeldelinks für die Verwendung in Apps und unterstützt das Konzept von Administratoren und Funktionen, die nur für Administratoren zugänglich sind. Zur Verbesserung der Anwendungsportabilität empfiehlt Google Cloud die Migration von alten gebündelten App Engine-Diensten zu eigenständigen Cloud-Diensten, z. B. vom Nutzerdienst zur Cloud Identity Platform.

Identity Platform basiert auf Firebase Authentication und bietet eine Reihe von Unternehmensfunktionen wie Multi-Faktor-Authentifizierung, OIDC und Unterstützung der SAML-SSO, Mehrmandantenfähigkeit, 99, 95% SLA und mehr. Diese Unterschiede werden auch auf der Produktvergleichsseite für Identity Platform und Firebase Authentication aufgezeigt. Beide Produkte haben deutlich mehr Funktionen als der Nutzerdienst.

In diesem Codelab für Modul 21 wird gezeigt, wie die Nutzerauthentifizierung der App vom Nutzerdienst auf Funktionen der Identity Platform umgestellt wird, die die in Modul 20 gezeigten Funktionen am besten widerspiegeln. In Modul 21 wird auch die Migration von App Engine NDB zu Cloud NDB für den Datastore-Zugriff beschrieben. Dabei wird die Migration von Modul 2 wiederholt.

Während der Code von Modul 20 „beworben“ wird als Python 2-Beispielanwendung, ist die Quelle selbst mit Python 2 und 3 kompatibel. Das ist auch nach der Migration zu Identity Platform (und Cloud NDB) hier in Modul 21 so. Sie können den Nutzerdienst während des Upgrades auf Python 3 weiterhin verwenden, da die Migration zu Identity Platform optional ist. Im Codelab für Modul 17 und im Video erfahren Sie, wie Sie die gebündelten Dienste weiterhin verwenden und gleichzeitig auf Laufzeiten der 2. Generation wie Python 3 upgraden.

Diese Anleitung umfasst die folgenden Schritte:

  1. Einrichtung/Vorarbeit
  2. Konfiguration aktualisieren
  3. Anwendungscode ändern

3. Einrichtung/Vorarbeit

In diesem Abschnitt wird Folgendes erläutert:

  1. Cloud-Projekt einrichten
  2. Baseline-Beispiel-App abrufen
  3. Referenz-App noch einmal bereitstellen und validieren
  4. Neue Google Cloud-Dienste/APIs aktivieren

Mit diesen Schritten stellen Sie sicher, dass Sie mit funktionierendem Code beginnen, der für die Migration zu eigenständigen Cloud-Diensten bereit ist.

1. Projekt einrichten

Wenn Sie das Codelab für Modul 20 abgeschlossen haben, verwenden Sie dasselbe Projekt (und Code) wieder. Alternativ können Sie ein neues Projekt erstellen oder ein anderes vorhandenes Projekt wiederverwenden. Achten Sie darauf, dass das Projekt ein aktives Rechnungskonto und eine aktivierte App Engine-Anwendung hat. Halten Sie in diesem Codelab Ihre Projekt-ID bereit und verwenden Sie sie immer, wenn Sie auf die Variable PROJ_ID stoßen.

2. Baseline-Beispiel-App abrufen

Eine der Voraussetzungen ist eine funktionierende App Engine-App für Modul 20. Füllen Sie daher entweder das Codelab aus (empfohlen; Link oben) oder kopieren Sie den Code von Modul 20 aus dem Repository. Ganz gleich, ob Sie Ihre oder unsere verwenden – hier beginnen wir („START“). Dieses Codelab führt Sie durch die Migration und enthält zum Schluss Code, der dem im Repository-Ordner von Modul 21 („FINISH“) ähnelt.

Kopieren Sie den Repository-Ordner für Modul 20. Sie sollte wie unten dargestellt aussehen und möglicherweise einen lib-Ordner haben, wenn Sie das Codelab für Modul 20 ausgeführt haben:

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

3. Referenz-App noch einmal bereitstellen und validieren

Führen Sie die folgenden Schritte aus, um die Modul 20-Anwendung bereitzustellen:

  1. Löschen Sie den lib-Ordner, falls vorhanden, und führen Sie pip install -t lib -r requirements.txt aus, um ihn neu zu füllen. Wenn Sie Python 2 und 3 installiert haben, müssen Sie möglicherweise pip2 verwenden.
  2. Achten Sie darauf, dass das gcloud-Befehlszeilentool installiert und initialisiert und seine Nutzung geprüft hat.
  3. Wenn Sie die PROJ_ID nicht mit jedem gcloud-Befehl eingeben möchten, legen Sie zuerst gcloud config set project PROJ_ID für das Cloud-Projekt fest.
  4. Beispielanwendung mit gcloud app deploy bereitstellen
  5. Prüfen Sie, ob die Anwendung wie erwartet ohne Fehler ausgeführt wird. Wenn Sie das Codelab für Modul 20 abgeschlossen haben, werden in der App oben die Anmeldeinformationen des Nutzers (E-Mail-Adresse des Nutzers, mögliches „Administrator-Abzeichen“ und eine Anmelde-/Abmeldeschaltfläche) zusammen mit den letzten Besuchen angezeigt (siehe Abbildung unten).

907e64c19ef964f8.png

Wenn Sie sich als normaler Nutzer anmelden, werden die E-Mail-Adresse des Nutzers und die Schaltfläche ändert sich zu "Abmelden". Schaltfläche:

ad7b59916b69a035.png

Wenn Sie sich als Administrator anmelden, wird die E-Mail-Adresse des Nutzers zusammen mit dem Zusatz „(Admin)“ angezeigt daneben:

867bcb3334149e4.png

4. Neue Google Cloud APIs/Dienste aktivieren

Einführung

Die Anwendung in Modul 20 verwendet die App Engine NDB und Nutzer-APIs, gebündelte Dienste, für die keine zusätzliche Einrichtung erforderlich ist, aber eigenständige Cloud-Dienste tun dies. Die aktualisierte Anwendung verwendet sowohl die Cloud Identity Platform als auch Cloud Datastore (über die Cloud NDB-Clientbibliothek). Außerdem müssen wir die App Engine-Administratoren ermitteln, die die Cloud Resource Manager API verwenden.

Kosten

  • App Engine und Cloud Datastore haben "Immer kostenlos"- Stufen berechnet. Solange Sie unter diesen Limits bleiben, sollten Ihnen durch das Ausführen dieser Anleitung keine Kosten entstehen. Weitere Informationen finden Sie auch auf der Seite App Engine – Preise und Cloud Datastore – Preise.
  • Die Nutzung der Cloud Identity Platform wird je nach Anzahl der monatlich aktiven Nutzer oder Authentifizierungsüberprüfungen abgerechnet. irgendeine Version von „kostenlos“ ist für jedes Nutzungsmodell verfügbar. Weitere Informationen finden Sie auf der Preisseite. Während App Engine und Cloud Datastore eine Abrechnung erfordern, erfordert die Nutzung von GCIP allein keine Aktivierung der Abrechnung, solange Sie die kostenlosen Tageskontingente nicht überschreiten. Dies sollten Sie bei Cloud-Projekten berücksichtigen, für die keine Cloud APIs/Dienste erforderlich sind.
  • Die Verwendung der Cloud Resource Manager API ist gemäß der Preisübersicht größtenteils kostenlos.

Nutzer aktivieren Cloud APIs über die Cloud Console oder die Befehlszeile (über den gcloud-Befehl, Teil des Cloud SDK), je nach Ihren Anforderungen. Beginnen wir mit den Cloud Datastore API und der Cloud Resource Manager API.

Über die Cloud Console

Rufen Sie in der Cloud Console die Seite API Manager-Bibliothek (für das richtige Projekt) auf und suchen Sie über die Suchleiste nach einer API. c7a740304e9d35b.png

Aktivieren Sie diese APIs:

Klicken Sie für jede API auf die Schaltfläche Aktivieren. Möglicherweise werden Sie aufgefordert, Zahlungsinformationen einzugeben. Hier ist als Beispiel die Seite für die Resource Manager API:

fc7bd8f4c49d12e5.png

Die Schaltfläche ändert sich zu Verwalten, wenn sie aktiviert wurde (in der Regel nach einigen Sekunden):

8eca12d6cc7b45b0.png

Aktivieren Sie Cloud Datastore auf dieselbe Weise:

83811599b110e46b.png

Über die Befehlszeile

Das Aktivieren von APIs über die Konsole ist zwar visuell informativ, einige bevorzugen jedoch die Befehlszeile. Sie können außerdem beliebig viele APIs gleichzeitig aktivieren. Führen Sie diesen Befehl aus, um sowohl die Cloud Datastore API als auch die Cloud Resource Manager API zu aktivieren und zu warten, bis der Vorgang abgeschlossen ist, wie hier dargestellt:

$ gcloud services enable cloudresourcemanager.googleapis.com datastore.googleapis.com
Operation "operations/acat.p2-aaa-bbb-ccc-ddd-eee-ffffff" finished successfully.

Möglicherweise werden Sie aufgefordert, Zahlungsinformationen einzugeben.

Die „URLs“ werden für jede im Befehl oben verwendete API als API-Dienstnamen bezeichnet. Sie finden sie unten auf der Bibliotheksseite der jeweiligen API. Wenn Sie andere Cloud APIs für Ihre eigenen Anwendungen aktivieren möchten, finden Sie die jeweiligen Dienstnamen auf den entsprechenden API-Seiten. Mit diesem Befehl werden alle Dienstnamen für APIs aufgelistet, die Sie aktivieren können:

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

Wenn Sie die oben genannten Schritte ausgeführt haben, kann unser Beispiel jetzt in der Cloud Console oder über die Befehlszeile auf diese APIs zugreifen. Als Nächstes aktivieren Sie die Cloud Identity Platform und nehmen die erforderlichen Änderungen am Code vor.

Cloud Identity Platform aktivieren und einrichten (nur Cloud Console)

Die Cloud Identity Platform ist ein Marketplace-Dienst, weil sie eine Verbindung zu einer Ressource außerhalb von Google Cloud herstellt oder von dieser abhängig ist, z. B. Firebase Authentication. Derzeit können Marketplace-Dienste nur über die Cloud Console aktiviert werden. Gehen Sie dazu so vor:

  1. Rufen Sie im Cloud Marketplace die Seite „Cloud Identity Platform“ auf und klicken Sie dort auf die Schaltfläche Aktivieren. Führen Sie ein Upgrade von Firebase Authentication durch, wenn Sie dazu aufgefordert werden. Dadurch werden zusätzliche Funktionen freigeschaltet, z. B. die weiter oben im Abschnitt Hintergrund beschriebenen. Auf der Marketplace-Seite ist die Schaltfläche Aktivieren markiert: 28475f1c9b29de69.png
  2. Sobald Identity Platform aktiviert ist, werden Sie automatisch zur Seite Identity Providers (Identitätsanbieter) weitergeleitet. Falls nicht, rufen Sie die Seite über diesen Link auf. fc2d92d42a5d1dd7.png
  3. Aktivieren Sie den Google Auth-Anbieter. Falls noch kein Anbieter eingerichtet wurde, klicken Sie auf Anbieter hinzufügen und wählen Sie Google aus. Wenn Sie zu diesem Bildschirm zurückkehren, sollte der Eintrag Google aktiviert sein. Google ist der einzige Authentifizierungsanbieter, den wir in dieser Anleitung verwenden, um den App Engine-Nutzerdienst als einfachen Google Log-in-Dienst zu spiegeln. In Ihren eigenen Apps können Sie zusätzliche Authentifizierungsanbieter aktivieren.
  4. Wenn Sie Google und einen anderen Authentifizierungsanbieter ausgewählt und eingerichtet haben, klicken Sie auf Details zur Einrichtung der Anwendung. Kopieren Sie dann im Dialogfeld zur Sicherstellung die apiKey und authDomain im config-Objekt auf dem Tab „Web“. Speichern Sie beide an einem sicheren Ort. Warum kopierst du nicht einfach alles? Das Snippet in diesem Dialogfeld ist hartcodiert und veraltet. Speichern Sie einfach die wichtigsten Bits und verwenden Sie sie in unserem Code mit mehr gleichzeitiger Firebase Auth-Nutzung. Nachdem Sie die Werte kopiert und an einem sicheren Ort gespeichert haben, klicken Sie auf die Schaltfläche Schließen, um die Einrichtung abzuschließen. bbb09dcdd9be538e.png

4. Konfiguration aktualisieren

Konfigurationsaktualisierungen umfassen sowohl das Ändern verschiedener Konfigurationsdateien als auch die Erstellung des Äquivalents von App Engine innerhalb des Cloud Identity Platform-Ökosystems.

appengine_config.py

  • Wenn Sie ein Upgrade auf Python 3 durchführen, löschen Sie appengine_config.py
  • Wenn Sie eine Modernisierung auf Identity Platform planen, aber bei Python 2 bleiben, löschen Sie die Datei nicht. Stattdessen werden wir sie später während des Python 2-Backports aktualisieren.

requirements.txt

In der Datei requirements.txt von Modul 20 wurde nur Flask aufgeführt. Fügen Sie für Modul 21 die folgenden Pakete hinzu:

Der Inhalt von requirements.txt sollte jetzt so aussehen:

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

app.yaml

  • Bei einem Upgrade auf Python 3 wird die Datei app.yaml vereinfacht. Entfernen Sie alles außer der Laufzeitanweisung und legen Sie dafür eine derzeit unterstützte Version von Python 3 fest. Für das Beispiel wird derzeit Version 3.10 verwendet.
  • Wenn Sie bei Python 2 bleiben, ergreifen Sie hier noch keine Maßnahmen.

VORHER:

runtime: python27
threadsafe: yes
api_version: 1

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

Die Beispiel-App für Modul 20 hat keine Handler für statische Dateien. Wenn Ihre Apps dies tun, lassen Sie sie unverändert. Sie können bei Bedarf alle Ihre Skript-Handler entfernen oder sie einfach dort zu Referenzzwecken belassen, solange Sie deren Handles zu auto ändern. Eine Beschreibung hierzu finden Sie in der Migrationsanleitung für app.yaml. Durch diese Änderungen wird die aktualisierte app.yaml für Python 3 so vereinfacht:

NACHHER:

runtime: python310

Weitere Konfigurationsaktualisierungen

Unabhängig davon, ob Sie bei Python 2 bleiben oder zu Python 3 portieren, sollten Sie einen lib-Ordner löschen, wenn Sie ihn haben.

5. Anwendungscode ändern

In diesem Abschnitt wird die Hauptanwendungsdatei main.py aktualisiert. Dadurch wird die Verwendung des App Engine-Nutzerdienstes durch die Cloud Identity Platform ersetzt. Nachdem Sie die Hauptanwendung aktualisiert haben, aktualisieren Sie auch die Webvorlage templates/index.html.

Importe und Initialisierung aktualisieren

Führen Sie die folgenden Schritte aus, um die Importe zu aktualisieren und Anwendungsressourcen zu initialisieren:

  1. Ersetzen Sie für die Importe App Engine NDB durch Cloud NDB.
  2. Importieren Sie neben Cloud NDB auch Cloud Resource Manager.
  3. Die Identity Platform basiert auf Firebase Auth. Importieren Sie daher das Firebase Admin SDK.
  4. Cloud APIs erfordern die Verwendung eines API-Clients. Initiieren Sie ihn daher für Cloud NDB direkt nach der Initialisierung von Flask.

Das Cloud Resource Manager-Paket wird zwar hier importiert, wir werden es aber zu einem späteren Zeitpunkt bei der App-Initialisierung verwenden. Nachfolgend sehen Sie die Importe und Initialisierungen aus Modul 20, gefolgt von den Abschnitten, die nach der Implementierung der obigen Änderungen aussehen sollten:

VORHER:

from flask import Flask, render_template, request
from google.appengine.api import users
from google.appengine.ext import ndb

app = Flask(__name__)

NACHHER:

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()

Unterstützung für App Engine-Administratoren

Es gibt zwei Komponenten, die der App hinzugefügt werden müssen, um die Erkennung von Administratoren zu unterstützen:

  • _get_gae_admins(): fasst eine Reihe von Administratoren zusammen einmal aufgerufen und gespeichert
  • is_admin(): prüft, ob der angemeldete Nutzer ein Administrator ist aufgerufen bei jeder Nutzeranmeldung

Die Dienstprogrammfunktion _get_gae_admins() ruft die Resource Manager API auf, um die aktuelle Cloud IAM-allow-policy abzurufen. In der Zulassungsrichtlinie wird festgelegt und erzwungen, welche Rollen welchen Hauptkonten gewährt werden (menschliche Nutzer, Dienstkonten usw.). Die Einrichtung umfasst Folgendes:

  • Cloud-Projekt-ID (PROJ_ID) wird abgerufen
  • Resource Manager API-Client erstellen (rm_client)
  • Einen (schreibgeschützten) Satz von App Engine-Administratorrollen erstellen (_TARGETS)

Der Resource Manager benötigt die Cloud-Projekt-ID. Importieren Sie daher google.auth.default() und rufen Sie diese Funktion auf, um die Projekt-ID abzurufen. Dieser Aufruf enthält einen Parameter, der ähnlich wie eine URL aussieht, aber ein OAuth2-Berechtigungsbereich ist. Wenn Sie Anwendungen in der Cloud ausführen, z. B. auf einer Compute Engine-VM oder in einer App Engine-Anwendung, wird ein Standarddienstkonto mit umfassenden Berechtigungen bereitgestellt. Gemäß der Best Practice der geringsten Berechtigung empfehlen wir, eigene nutzerverwaltete Dienstkonten zu erstellen.

Für API-Aufrufe empfiehlt es sich, den Umfang Ihrer Apps auf das für eine ordnungsgemäße Funktion erforderliche zusätzliche Minimum zu reduzieren. Der Aufruf der Resource Manager API ist get_iam_policy(). Für den Betrieb ist einer der folgenden Bereiche erforderlich:

  • 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

Die Beispiel-App benötigt nur Lesezugriff auf die Zulassungsliste. Die Richtlinie wird dadurch nicht geändert und es wird kein Zugriff auf das gesamte Projekt benötigt. Das bedeutet, dass die App keine der ersten drei erforderlichen Berechtigungen benötigt. Die letzte ist alles, was erforderlich ist, und das wird für die Beispiel-App implementiert.

Der Haupttext der Funktion erstellt einen leeren Satz von Administratornutzern (admins), ruft den allow_policy über get_iam_policy() ab und durchläuft alle Bindungen, speziell nach App Engine-Administratorrollen:

  • roles/viewer
  • roles/editor
  • roles/owner
  • roles/appengine.appAdmin

Für jede gefundene Zielrolle werden die Nutzer sortiert, die zu dieser Rolle gehören, und sie werden zur Gesamtgruppe der Administratoren hinzugefügt. Er endet, indem alle gefundenen und im Cache gespeicherten Administratoren für die Lebensdauer dieser App Engine-Instanz als Konstante (_ADMINS) zurückgegeben werden. Wir sehen diesen Anruf in Kürze.

Fügen Sie die folgende Funktionsdefinition _get_gae_admins() zu main.py direkt unter dem Instanziieren des Cloud NDB API-Clients (ds_client) hinzu:

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

Wenn sich Nutzer in der App anmelden, geschieht Folgendes:

  1. Nachdem sich ein Nutzer in Firebase angemeldet hat, wird über die Webvorlage eine schnelle Prüfung durchgeführt.
  2. Wenn sich der Authentifizierungsstatus in der Vorlage ändert, wird ein fetch()-Aufruf im Ajax-Stil an /is_admin gesendet, dessen Handler die nächste Funktion (is_admin()) ist.
  3. Das Firebase-ID-Token wird im POST-Text an is_admin() übergeben, das es aus den Headern holt und das Firebase Admin SDK aufruft, um es zu validieren. Wenn es sich um einen gültigen Nutzer handelt, extrahieren Sie seine E-Mail-Adresse und prüfen Sie, ob es sich um einen Administrator handelt.
  4. Das boolesche Ergebnis wird dann als erfolgreicher 200 an die Vorlage zurückgegeben.

Fügen Sie is_admin() in main.py direkt nach _get_gae_admins() hinzu:

@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

Der gesamte Code aus beiden Funktionen ist erforderlich, um die im Nutzerdienst verfügbare Funktionalität zu replizieren, insbesondere die Funktion is_current_user_admin(). Dieser Funktionsaufruf in Modul 20 hat im Gegensatz zu Modul 21, in dem wir eine Ersatzlösung implementieren, den Großteil der Arbeit abgenommen. Die gute Nachricht ist, dass die Anwendung nicht mehr von einem reinen App Engine-Dienst abhängig ist. Sie können Ihre Anwendungen also zu Cloud Run oder anderen Diensten verschieben. Darüber hinaus können Sie auch die Definition von „Administrator“ ändern. für Ihre eigenen Apps, indem Sie einfach zu den gewünschten Rollen in _TARGETS wechseln, während der Nutzerdienst für die App Engine-Administratorrollen hartcodiert ist.

Firebase Auth initialisieren und App Engine-Administratoren im Cache speichern

Wir hätten Firebase Auth ganz oben in der Nähe der Stelle initialisiert können, an der die Flask-App initialisiert und der Cloud NDB API-Client erstellt wurde. Dies war jedoch erst nötig, wenn der gesamte Administratorcode definiert wurde. Nachdem _get_gae_admins() definiert wurde, können Sie die Liste entsprechend aufrufen, um die Liste der Administratoren im Cache zu speichern.

Fügen Sie diese Zeilen direkt unter dem Funktionstext von is_admin() ein:

# initialize Firebase and fetch set of App Engine admins
initialize_app()
_ADMINS = _get_gae_admins()

Aktualisierungen des Datenmodells aufrufen

Das Visit-Datenmodell ändert sich nicht. Für den Datastore-Zugriff ist die explizite Verwendung des Cloud NDB API-Clientkontextmanagers ds_client.context() erforderlich. In Code bedeutet dies, dass Datastore-Aufrufe sowohl in store_visit() als auch in fetch_visits() in Python-with-Blöcken umschlossen werden. Dieses Update ist mit Modul 2 identisch. Nehmen Sie die folgenden Änderungen vor:

VORHER:

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)

NACHHER:

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)

Anmeldelogik für Nutzer in Webvorlage verschieben

Der App Engine-Nutzerdienst ist serverseitig, während Firebase Auth und die Cloud Identity Platform vorwiegend clientseitig sind. Daher wird ein Großteil des Nutzerverwaltungscodes in der App für Modul 20 in die Webvorlage für Modul 21 verschoben.

In main.py werden vom Webkontext fünf wesentliche Daten an die Vorlage übergeben. Die ersten vier sind an die Nutzerverwaltung gebunden und unterscheiden sich je nachdem, ob der Nutzer angemeldet ist oder nicht:

  • who: E-Mail-Adresse des Nutzers, wenn angemeldet, andernfalls Nutzer
  • admin: Badge (Administrator), wenn der angemeldete Nutzer ein Administrator ist
  • sign – Schaltfläche Anmelden oder Abmelden anzeigen
  • link – An- oder Abmeldelinks beim Klicken auf eine Schaltfläche
  • visits – letzte Besuche

VORHER:

@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)

Die gesamte Nutzerverwaltung wird auf die Webvorlage verlagert, sodass wir nur noch die Besuche erhalten, sodass der Haupt-Handler wieder auf den vorherigen Zustand aus der App des Moduls 1 zurückgreift:

NACHHER:

@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)

Webvorlage aktualisieren

Wie sehen alle Aktualisierungen aus dem vorherigen Abschnitt in der Vorlage aus? Wir haben hauptsächlich die Nutzerverwaltung von der App zu Firebase Auth verlagert, das in der Vorlage ausgeführt wird, und einen Teil des Codes, den wir in JavaScript verschoben haben. Der Messwert „main.py“ ist stark gesunken, daher sollten Sie für templates/index.html ein ähnliches Wachstum erwarten.

VORHER:

<!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>

Ersetzen Sie die gesamte Webvorlage durch den folgenden Inhalt:

NACHHER:

<!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>

Dieser HTML-Text umfasst viele Komponenten, die wir uns Stück für Stück ansehen können.

Firebase-Importe

Importieren Sie die erforderlichen Firebase-Komponenten nach dem Seitentitel im Header des HTML-Dokuments. Aus Effizienzgründen sind Firebase-Komponenten jetzt in mehrere Module unterteilt. Der Code zum Initialisieren von Firebase wird aus dem Hauptmodul der Firebase-App importiert, während Funktionen zur Verwaltung von Firebase-Auth, Google als Authentifizierungsanbieter, An- und Abmeldung und Authentifizierungsstatus „Callback“ zur Änderung des Authentifizierungsstatus dienen. werden alle aus dem Firebase Auth-Modul importiert:

<!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-Konfiguration

Im Rahmen des Einrichtungsteils von Identity Platform in dieser Anleitung haben Sie zuvor die apiKey und die authDomain aus dem Dialogfeld Details zur Anwendungseinrichtung gespeichert. Fügen Sie diese Werte im nächsten Abschnitt der Variablen firebaseConfig hinzu. Einen Link zu ausführlicheren Anweisungen finden Sie in den Kommentaren:

// 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-Initialisierung

Im nächsten Abschnitt wird Firebase mit diesen Konfigurationsinformationen initialisiert.

// initialize Firebase app & auth components
initializeApp(firebaseConfig);
var auth = getAuth();
var provider = new GoogleAuthProvider();
//provider.setCustomParameters({prompt: 'select_account'});

Dadurch wird festgelegt, ob Google als Authentifizierungsanbieter verwendet werden kann. Außerdem wird eine auskommentierte Option zum Anzeigen der Kontoauswahl bereitgestellt, selbst wenn in Ihrer Browsersitzung nur ein Google-Konto registriert ist. Mit anderen Worten: Wenn Sie mehrere Konten haben, wird die Kontoauswahl angezeigt. Wie erwartet: a38369389b7c4c7e.png Wenn sich jedoch nur ein Nutzer in der Sitzung befindet, wird der Anmeldevorgang automatisch und ohne Nutzerinteraktion abgeschlossen. (Das Pop-up wird angezeigt und dann wieder ausgeblendet.) Sie können erzwingen, dass das Dialogfeld für die Kontoauswahl für einen Nutzer angezeigt wird, anstatt sich direkt in der App anzumelden. Entfernen Sie dazu die Kommentarzeichen in der Zeile mit dem benutzerdefinierten Parameter. Wenn diese Option aktiviert ist, wird auch bei der Anmeldung eines einzelnen Nutzers die Kontoauswahl aufgerufen: b75624cb68d94557.png

An- und Abmeldefunktionen

Die nächsten Codezeilen bilden die Funktionen für die Klicks auf die Anmelde- oder Abmeldeschaltfläche:

// define login and logout button functions
function login() {
    signInWithPopup(auth, provider);
};

function logout() {
    signOut(auth);
};

An- und Abmeldeaktionen

Der letzte größere Abschnitt in diesem <script>-Block ist die Funktion, die bei jeder Authentifizierungsänderung (Anmeldung oder Abmeldung) aufgerufen wird.

// 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>

Code in Modul 20, der bestimmt, ob ein „angemeldeter Nutzer“ gesendet werden soll Vorlagenkontext und „Nutzer abgemeldet“ Kontext hierüber wird. Die Bedingung oben führt zu true, wenn der Nutzer sich erfolgreich angemeldet hat. Es werden die folgenden Aktionen ausgelöst:

  1. Die E-Mail-Adresse des Nutzers ist für die Anzeige eingerichtet.
  2. Die Schaltfläche Anmelden ändert sich zu Abmelden.
  3. /is_admin wird im Ajax-Stil aufgerufen, um zu bestimmen, ob das (admin)-Administratorlogo verwendet werden soll.

Wenn der Nutzer abmeldet, wird die else-Klausel ausgeführt, um alle Nutzerinformationen zurückzusetzen:

  1. Nutzername auf user festgelegt
  2. Alle Admin-Badges wurden entfernt
  3. Die Schaltfläche Abmelden wurde wieder zu Anmelden geändert.

Vorlagenvariablen

Nach dem Ende des Header-Abschnitts beginnt der Haupttext mit den Vorlagenvariablen, die durch HTML-Elemente ersetzt werden, die sich nach Bedarf ändern:

  1. Angezeigter Nutzername
  2. (admin)-Admin-Badge (falls zutreffend)
  3. Schaltfläche Anmelden oder Abmelden
<body>
<p>
Welcome, <span id="who"></span> <span id="admin"><code>(admin)</code></span>
<button id="logbtn"></button>
</p><hr>

Letzte Besuche und Variablen für HTML-Elemente

Der Code für die letzten Besuche ändert sich nicht und mit dem letzten <script>-Block werden die Variablen für die HTML-Elemente festgelegt, die sich für die An- und Abmeldung ändern, die oben aufgeführt sind:

<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>

Damit sind die Änderungen abgeschlossen, die in der Anwendung und der Webvorlage für den Wechsel von App Engine NDB und Users APIs zu Cloud NDB und Identity Platform sowie für das Upgrade auf Python 3 erforderlich sind. Glückwunsch zu Ihrer neuen Beispiel-App für Modul 21. Unsere Version steht im Repository-Ordner für Modul 21b zur Einsicht bereit.

Der nächste Teil des Codelabs ist optional (*) und gilt nur für Nutzer, deren Apps auf Python 2 bleiben müssen. Er führt Sie durch die erforderlichen Schritte, um zu einer funktionierenden Anwendung mit Python 2 Module 21 zu gelangen.

6. *Python 2-Backport

Dieser optionale Abschnitt richtet sich an Entwickler, die eine Identity Platform-Migration durchführen, aber weiterhin die Python 2-Laufzeit verwenden müssen. Wenn dies für Sie nicht relevant ist, überspringen Sie diesen Abschnitt.

Um eine funktionierende Python 2-Version der Modul 21-Anwendung zu erstellen, benötigen Sie Folgendes:

  1. Laufzeitanforderungen: Konfigurationsdateien, die Python 2 unterstützen und Änderungen an der Hauptanwendung erforderlich machen, um Python 3-Inkompatibilitäten zu vermeiden
  2. Geringfügige Änderung der Bibliothek: Python 2 wurde eingestellt, bevor einige erforderliche Funktionen der Resource Manager-Clientbibliothek hinzugefügt wurden. Daher benötigen Sie eine alternative Methode, um auf diese fehlende Funktion zuzugreifen.

Beginnen wir mit der Konfiguration.

appengine_config.py wiederherstellen

Zu Beginn dieser Anleitung wurden Sie zum Löschen von appengine_config.py aufgefordert, da es nicht von der Python 3-App Engine-Laufzeit verwendet wird. Bei Python 2 muss dies nicht nur beibehalten werden, sondern auch die appengine_config.py von Modul 20 muss aktualisiert werden, um die Verwendung von integrierten Drittanbieterbibliotheken, nämlich grpcio und setuptools, zu unterstützen. Diese Pakete sind erforderlich, wenn Ihre App Engine-Anwendung Cloud-Clientbibliotheken wie die für Cloud NDB und Cloud Resource Manager verwendet.

Du fügst diese Pakete gleich zu app.yaml hinzu, aber damit deine App darauf zugreifen kann, muss die Funktion pkg_resources.working_set.add_entry() von setuptools aufgerufen werden. Dadurch können kopierte (selbst gebündelte oder übernommene) Drittanbieterbibliotheken, die im Ordner lib installiert sind, mit integrierten Bibliotheken kommunizieren.

Implementiere die folgenden Aktualisierungen in deiner appengine_config.py-Datei, um diese Änderungen zu übernehmen:

VORHER:

from google.appengine.ext import vendor

# Set PATH to your libraries folder.
PATH = 'lib'
# Add libraries installed in the PATH folder.
vendor.add(PATH)

Dieser Code allein reicht nicht aus, um die Verwendung von setuptools und grpcio zu unterstützen. Ein paar mehr Zeilen sind erforderlich. Aktualisieren Sie appengine_config.py, damit es so aussieht:

NACHHER:

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)

Weitere Informationen zu Änderungen, die zur Unterstützung von Cloud-Clientbibliotheken erforderlich sind, finden Sie in der Dokumentation zum Migrieren gebündelter Dienste.

app.yaml

Ähnlich wie appengine_config.py muss die Datei app.yaml auf eine Datei zurückgesetzt werden, die Python 2 unterstützt. Beginnen wir mit dem ursprünglichen Modul 20 app.yaml:

VORHER:

runtime: python27
threadsafe: yes
api_version: 1

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

Neben setuptools und grpcio gibt es, wie bereits erwähnt, eine Abhängigkeit (nicht explizit mit der Identity Platform-Migration verknüpft), die die Verwendung der Cloud Storage-Clientbibliothek erfordert und die ein weiteres integriertes Drittanbieterpaket, ssl, benötigt. Fügen Sie alle drei in einem neuen libraries-Abschnitt hinzu und wählen Sie die Kategorie „Neueste“ aus. verfügbaren Versionen dieser Pakete an app.yaml:

NACHHER:

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

In Modul 21 haben wir Google Auth, Cloud NDB, Cloud Resource Manager und das Firebase Admin SDK zu Python 3 requirements.txt hinzugefügt. Die Situation für Python 2 ist komplexer:

  • Die Resource Manager API bietet die für die Beispielanwendung erforderliche Funktion für Zulassungsrichtlinien. Leider war diese Unterstützung in der endgültigen Python 2-Version der Cloud Resource Manager-Clientbibliothek noch nicht verfügbar. Sie ist nur in der Python 3-Version verfügbar.
  • Daher ist eine alternative Möglichkeit erforderlich, über die API auf diese Funktion zuzugreifen. Als Lösung können Sie für die Kommunikation mit der API die Clientbibliothek der Google APIs auf niedrigerer Ebene verwenden. Ersetzen Sie google-cloud-resource-manager durch das untergeordnete google-api-python-client-Paket, um zu dieser Clientbibliothek zu wechseln.
  • Da Python 2 eingestellt wurde, muss die Abhängigkeitsgrafik, die Modul 21 unterstützt, bestimmte Pakete für bestimmte Versionen sperren. Einige Pakete müssen aufgerufen werden, auch wenn sie nicht in der app.yaml von Python 3 angegeben sind.

VORHER:

flask

Beginnen Sie mit Modul 20 requirements.txt und aktualisieren Sie sie für eine funktionierende Modul 21-App wie folgt:

NACHHER:

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

Das Paket und die Versionsnummern werden im Repository aktualisiert, wenn sich Abhängigkeiten ändern. Diese app.yaml reicht jedoch für eine funktionierende Anwendung zum Zeitpunkt dieses Schreibens aus.

Weitere Konfigurationsaktualisierungen

Wenn Sie den Ordner lib in diesem Codelab noch nicht gelöscht haben, tun Sie dies jetzt. Führen Sie mit dem neu aktualisierten requirements.txt den folgenden Befehl aus, um diese Anforderungen in lib zu installieren:

pip install -t lib -r requirements.txt  # or pip2

Wenn Sie sowohl Python 2 als auch 3 auf Ihrem Entwicklungssystem installiert haben, müssen Sie möglicherweise pip2 anstelle von pip verwenden.

Anwendungscode ändern

Glücklicherweise befinden sich die meisten erforderlichen Änderungen in den Konfigurationsdateien. Die einzige Änderung am Anwendungscode ist ein geringfügiges Update, um die untergeordnete Google API-Clientbibliothek anstelle der Resource Manager-Clientbibliothek für den Zugriff auf die API zu verwenden. Die Webvorlage „templates/index.html“ muss nicht aktualisiert werden.

Importe und Initialisierung aktualisieren

Ersetzen Sie die Resource Manager-Clientbibliothek (google.cloud.resourcemanager) durch die Google API-Clientbibliothek (googleapiclient.discovery), wie unten dargestellt:

VORHER:

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

NACHHER:

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

Unterstützung für App Engine-Administratoren

In _get_gae_admins() sind einige Änderungen erforderlich, um die Verwendung der untergeordneten Clientbibliothek zu unterstützen. Besprechen wir zunächst, was sich ändert, und stellen Ihnen dann den gesamten zu aktualisierenden Code zur Verfügung.

Für den Python 2-Code müssen sowohl die Anmeldedaten als auch die von google.auth.default() zurückgegebene Projekt-ID verwendet werden. Da die Anmeldedaten in Python 3 nicht verwendet werden, wurden sie einer generischen Unterstrich-Variable ( _) zugewiesen. Da der Unterstrich für die Python 2-Version erforderlich ist, ändern Sie ihn in CREDS. Anstatt einen Resource Manager API-Client zu erstellen, erstellen Sie einen API-Dienstendpunkt, ähnlich wie bei einem API-Client. Daher behalten wir denselben Variablennamen (rm_client). Ein Unterschied besteht darin, dass für die Instanziierung eines Dienstendpunkts Anmeldedaten (CREDS) erforderlich sind.

Diese Änderungen spiegeln sich im folgenden Code wider:

VORHER:

_, PROJ_ID = default(  # Application Default Credentials and project ID
        ['https://www.googleapis.com/auth/cloudplatformprojects.readonly'])
rm_client = resourcemanager.ProjectsClient()

NACHHER:

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)

Der andere Unterschied besteht darin, dass die Resource Manager-Clientbibliothek Zulassungsrichtlinienobjekte zurückgibt, die die Schreibweise mit gepunkteten Attributen verwenden. Die untergeordnete Clientbibliothek hingegen gibt Python-Wörterbücher zurück, in denen eckige Klammern ( [ ]) verwendet werden. Verwenden Sie beispielsweise binding.role für die Resource Manager-Clientbibliothek und binding['role'] für die untergeordnete Bibliothek. Bei Ersteren wird auch „Unterstrich_separate“ verwendet. gegenüber der untergeordneten Bibliothek, die „CamelCased“ bevorzugt, und eine etwas andere Art zur Übergabe von API-Parametern.

Diese Nutzungsunterschiede sind im Folgenden aufgeführt:

VORHER:

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)

NACHHER:

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'])

Wenn Sie alle diese Änderungen zusammenfassen, ersetzen Sie _get_gae_admins() von Python 3 durch diese entsprechende Python 2-Version:

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

Die Funktion is_admin() muss nicht aktualisiert werden, da sie auf _get_gae_admins() basiert, das bereits aktualisiert wurde.

Damit sind die Änderungen abgeschlossen, die für die Rückportierung der Anwendung „Python 3 Modul 21“ zu Python 2 erforderlich sind. Herzlichen Glückwunsch zu Ihrer aktualisierten Beispiel-App für Modul 21. Sie finden den gesamten Code im Repository-Ordner für Modul 21a.

7. Zusammenfassung/Bereinigung

In den letzten Schritten im Codelab prüfen Sie, ob Hauptkonten (Nutzer oder Dienstkonten), die diese App ausführen, die entsprechenden Berechtigungen haben. Stellen Sie dann die App bereit, um zu prüfen, ob sie wie vorgesehen funktioniert und die Änderungen in der Ausgabe übernommen werden.

Kann IAM-Zulassungsrichtlinien lesen

Wir haben Ihnen bereits die vier Rollen vorgestellt, die erforderlich sind, um als App Engine-Administrator anerkannt zu werden. Jetzt müssen Sie sich jedoch mit einer fünften vertraut machen:

  • roles/viewer
  • roles/editor
  • roles/owner
  • roles/appengine.appAdmin
  • roles/resourcemanager.projectIamAdmin (für Hauptkonten, die auf die IAM-Zulassungsrichtlinie zugreifen)

Mit der Rolle roles/resourcemanager.projectIamAdmin können Hauptkonten ermitteln, ob ein Endnutzer Mitglied einer der App Engine-Administratorrollen ist. Ohne Mitgliedschaft in roles/resourcemanager.projectIamAdmin schlagen Aufrufe der Cloud Resource Manager API zum Abrufen der Zulassungsliste fehl.

Sie müssen hier keine explizite Aktion ausführen, da Ihre App unter dem App Engine-Standarddienstkonto ausgeführt wird, dem automatisch die Mitgliedschaft in dieser Rolle gewährt wird. Auch wenn Sie in der Entwicklungsphase das Standarddienstkonto verwenden, empfehlen wir dringend, ein vom Nutzer verwaltetes Dienstkonto mit den Mindestberechtigungen zu erstellen und zu verwenden, die für das ordnungsgemäße Funktionieren Ihrer App erforderlich sind. Führen Sie den folgenden Befehl aus, um einem solchen Dienstkonto Mitgliedschaft zu gewähren:

$ 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 ist die Cloud-Projekt-ID und USR_MGD_SVC_ACCT@PROJ_ID.iam.gserviceaccount.com ist das nutzerverwaltete Dienstkonto, das Sie für Ihre Anwendung erstellen. Mit diesem Befehl wird die aktualisierte IAM-Richtlinie für Ihr Projekt ausgegeben, mit der Sie bestätigen können, dass das Dienstkonto eine Mitgliedschaft in roles/resourcemanager.projectIamAdmin hat. Weitere Informationen finden Sie in der Referenzdokumentation. Sie müssen diesen Befehl in diesem Codelab nicht ausführen, aber speichern Sie ihn als Referenz für die Modernisierung Ihrer eigenen Anwendungen.

Anwendung bereitstellen und prüfen

Laden Sie Ihre Anwendung mit dem Standardbefehl gcloud app deploy in die Cloud hoch. Nach der Bereitstellung sollten die Funktionen fast mit der App Engine-App identisch sein, mit der Ausnahme, dass Sie den App Engine-Nutzerdienst erfolgreich durch die Cloud Identity Platform (und Firebase Auth) für die Nutzerverwaltung ersetzt haben:

83ae745121d70.png

Ein Unterschied, den Sie im Vergleich zu Modul 20 feststellen werden, besteht darin, dass beim Klicken auf das Login ein Pop-up statt einer Weiterleitung angezeigt wird, wie in einigen der folgenden Screenshots dargestellt. Wie in Modul 20 unterscheidet sich das Verhalten jedoch geringfügig, je nachdem, wie viele Google-Konten im Browser registriert wurden.

Wenn keine Nutzer im Browser registriert sind oder ein einzelner Nutzer sich noch nicht angemeldet hat, wird ein allgemeines Pop-up-Fenster für die Google-Anmeldung angezeigt:

8437f5f3d489a942.png

Wenn ein einzelner Nutzer in Ihrem Browser registriert ist, sich aber an anderer Stelle anmeldet, wird kein Dialogfeld angezeigt (oder es öffnet sich und schließt sofort) und die App wird angemeldet, d. h., die E-Mail-Adresse des Nutzers und die Schaltfläche Abmelden werden angezeigt.

Manche Entwickler möchten eine Kontoauswahl bereitstellen, selbst für einen einzelnen Nutzer:

b75624cb68d94557.png

Um dies zu implementieren, entfernen Sie wie oben beschrieben die Kommentarzeichen in der Zeile provider.setCustomParameters({prompt: 'select_account'}); in der Webvorlage.

Wenn es mehrere Nutzer gibt, wird das Dialogfeld für die Kontoauswahl angezeigt (siehe unten). Wenn der Nutzer noch nicht angemeldet ist, wird er dazu aufgefordert. Wenn Sie bereits angemeldet sind, wird das Pop-up ausgeblendet und die App wird angemeldet.

c454455b6020d5e4.png

Der Anmeldestatus von Modul 21 sieht genauso aus wie die Benutzeroberfläche von Modul 20:

49ebe4dcc1eff11f.png

Dasselbe gilt, wenn sich ein Administrator angemeldet hat:

44302f35b39856eb.png

Im Gegensatz zu Modul 21 greift Modul 20 immer aus der App auf die Logik für den Inhalt der Webvorlage zu (serverseitiger Code). Ein Nachteil von Modul 20 besteht darin, dass ein Besuch registriert wird, wenn der Endnutzer die App zum ersten Mal aufruft, und ein weiterer Besuch, wenn sich ein Nutzer anmeldet.

In Modul 21 findet die Anmeldelogik nur in der Webvorlage (clientseitiger Code) statt. Es ist keine serverseitige Überprüfung erforderlich, um zu bestimmen, welche Inhalte angezeigt werden sollen. Der einzige Aufruf an den Server ist die Prüfung auf Administratoren, nachdem sich ein Endnutzer angemeldet hat. Durch Anmeldungen und Abmeldungen werden also keine zusätzlichen Besuche erfasst. Daher bleibt die Liste der letzten Besuche für Aktionen zur Nutzerverwaltung gleich. Beachten Sie, dass die obigen Screenshots dieselbe Gruppe von vier Besuchen für mehrere Nutzer-Logins zeigen.

Die Screenshots in Modul 20 veranschaulichen den "Doppelbesuchsfehler". am Anfang dieses Codelabs. Für jede Anmelde- oder Abmeldeaktion werden separate Besuchsprotokolle angezeigt. Überprüfen Sie die Zeitstempel des letzten Besuchs für jeden Screenshot, der die chronologische Reihenfolge zeigt.

Bereinigen

Allgemein

Falls Sie vorerst fertig sind, empfehlen wir Ihnen, Ihre App Engine-Anwendung zu deaktivieren, um Gebühren zu vermeiden. Wenn Sie jedoch weitere Tests oder Experimente durchführen möchten, bietet die App Engine-Plattform ein kostenloses Kontingent. Solange Sie diese Nutzungsstufe nicht überschreiten, sollten Ihnen keine Kosten in Rechnung gestellt werden. Das bezieht sich auf die Rechenleistung. Es können jedoch auch Gebühren für relevante App Engine-Dienste anfallen. Weitere Informationen finden Sie auf der Preisseite. Wenn diese Migration andere Cloud-Dienste betrifft, werden diese separat abgerechnet. Lesen Sie in beiden Fällen gegebenenfalls den Abschnitt „Speziell für dieses Codelab“. weiter unten.

Zur vollständigen Offenlegung fallen bei der Bereitstellung auf einer serverlosen Computing-Plattform von Google Cloud wie App Engine geringfügige Build- und Speicherkosten an. Für Cloud Build und Cloud Storage gibt es ein eigenes kostenloses Kontingent. Die Speicherung dieses Images verbraucht einen Teil dieses Kontingents. Möglicherweise leben Sie in einer Region, in der es keine solche kostenlose Stufe gibt. Achten Sie daher auf Ihre Speichernutzung, um potenzielle Kosten zu minimieren. Bestimmte Cloud Storage-„Ordner“ sollten Sie Folgendes überprüfen:

  • 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
  • Die oben angezeigten Speicherlinks hängen von deiner PROJECT_ID und deiner LOC-Adresse ab, z. B. „us“ wenn Ihre App in den USA gehostet wird.

Wenn Sie jedoch nicht mit dieser Anwendung oder anderen verwandten Migrations-Codelabs fortfahren und alles vollständig löschen möchten, beenden Sie Ihr Projekt.

Nur für dieses Codelab

Die unten aufgeführten Dienste gelten nur für dieses Codelab. Weitere Informationen finden Sie in der Dokumentation des jeweiligen Produkts:

  • Der App Engine Datastore-Dienst wird von Cloud Datastore (Cloud Firestore im Datastore-Modus) bereitgestellt, der ebenfalls eine kostenlose Stufe hat. Weitere Informationen finden Sie auf der Preisseite.
  • Die Nutzung der Cloud Identity Platform ist in gewisser Weise kostenlos, je nachdem, welche Dienste Sie nutzen. Weitere Informationen finden Sie auf der Preisseite.
  • Die Verwendung der Cloud Resource Manager API ist gemäß der Preisübersicht größtenteils kostenlos.

Nächste Schritte

Abgesehen von dieser Anleitung gibt es weitere Migrationsmodule, die sich auf die Umstellung von den gebündelten Legacy-Diensten konzentrieren:

  • Modul 2: von App Engine ndb zu Cloud NDB migrieren
  • Module 7–9: Migration von App Engine-Aufgabenwarteschlange (Push-Aufgaben) zu Cloud Tasks
  • Module 12–13: Migration von App Engine Memcache zu Cloud Memorystore
  • Module 15–16: Migration von App Engine Blobstore zu Cloud Storage
  • Module 18–19: Migration von App Engine-Aufgabenwarteschlange (Pull-Aufgaben) zu Cloud Pub/Sub

App Engine ist nicht mehr die einzige serverlose Plattform in Google Cloud. Wenn Sie eine kleine App Engine-Anwendung oder eine mit eingeschränkter Funktionalität haben und sie in einen eigenständigen Mikrodienst umwandeln möchten oder eine monolithische Anwendung in mehrere wiederverwendbare Komponenten aufteilen möchten, sind dies gute Gründe für einen Wechsel zu Cloud Functions. Wenn die Containerisierung Teil Ihres Workflows für die Anwendungsentwicklung geworden ist, insbesondere wenn sie aus einer CI/CD-Pipeline (Continuous Integration/Continuous Delivery oder Bereitstellung) besteht, sollten Sie eine Migration zu Cloud Run in Betracht ziehen. Diese Szenarien werden in den folgenden Modulen behandelt:

  • Migration von App Engine zu Cloud Functions: siehe Modul 11
  • Migration von App Engine zu Cloud Run: Siehe Modul 4 zum Containerisieren Ihrer Anwendung mit Docker oder Modul 5 zur Implementierung von Containern, Docker-Kenntnissen oder Dockerfile

Der Wechsel zu einer anderen serverlosen Plattform ist optional. Wir empfehlen Ihnen, die besten Optionen für Ihre Anwendungen und Anwendungsfälle zu erwägen, bevor Sie Änderungen vornehmen.

Unabhängig davon, welches Migrationsmodul Sie als Nächstes in Betracht ziehen, können Sie auf alle Inhalte der Serverless Migration Station (Codelabs, Videos, Quellcode [falls verfügbar]) über das Open-Source-Repository zugreifen. Im README des Repositorys finden Sie außerdem Informationen dazu, welche Migrationen berücksichtigt werden müssen und welche relevante „Reihenfolge“ Sie haben Migrationsmodule.

8. Zusätzliche Ressourcen

Nachfolgend finden Sie zusätzliche Ressourcen für Entwickler, die dieses oder verwandte Migrationsmodule näher kennenlernen möchten. Unten können Sie Feedback zu diesen Inhalten geben, Links zum Code und verschiedene hilfreiche Dokumentationen finden.

Probleme/Feedback mit Codelabs

Wenn Sie Probleme mit diesem Codelab feststellen, suchen Sie bitte zuerst nach dem Problem, bevor Sie es einreichen. Links zum Suchen und Erstellen neuer Ausgaben:

Migrationsressourcen

In der folgenden Tabelle finden Sie Links zu den Repository-Ordnern für Modul 20 (START) und Modul 21 (FINISH).

Codelab

Python 2

Python 3

Modul 20

code

(nicht zutreffend)

Modul 21 (dieses Codelab)

code

code

Onlinereferenzen

Im Folgenden finden Sie Ressourcen, die für diese Anleitung relevant sind:

Cloud Identity Platform und Cloud Marketplace

Cloud Resource Manager, Cloud IAM, Firebase Admin SDK

App Engine-Nutzer, App Engine NDB, Cloud NDB, Cloud Datastore

Weitere Referenzen zum Migrationsmodul

App Engine-Migration

App Engine-Plattform

Cloud SDK

Weitere Cloud-Informationen

Videos

Lizenz

Dieser Text ist mit einer Creative Commons Attribution 2.0 Generic License lizenziert.