Eseguire la migrazione dal servizio Utenti di App Engine a Cloud Identity Platform (modulo 21)

1. Panoramica

La serie di codelab Serverless Migration Station (esercitazioni pratiche e autonome) e i video correlati hanno lo scopo di aiutare gli sviluppatori serverless di Google Cloud a modernizzare le loro applicazioni guidandoli attraverso una o più migrazioni, principalmente abbandonando i servizi legacy. In questo modo, le tue app sono più portatili e hai più opzioni e flessibilità, il che ti consente di integrarti e accedere a una gamma più ampia di prodotti cloud e di eseguire più facilmente l'upgrade alle versioni più recenti del linguaggio. Sebbene inizialmente si concentri sui primi utenti di Cloud, principalmente gli sviluppatori di App Engine (ambiente standard), questa serie è abbastanza ampia da includere altre piattaforme serverless come Cloud Functions e Cloud Run o altrove, se applicabile.

Lo scopo di questo codelab è mostrare agli sviluppatori di App Engine Python 2 come eseguire la migrazione dall'API/servizio utenti App Engine a Cloud Identity Platform (GCIP). Esiste anche una migrazione implicita da App Engine NDB a Cloud NDB per l'accesso a Datastore (principalmente trattata nel modulo 2 della migrazione), nonché un upgrade a Python 3.

Il modulo 20 spiega come aggiungere l'utilizzo dell'API Users all'app di esempio del modulo 1. In questo modulo, prenderai l'app del modulo 20 completata e ne eseguirai la migrazione a Cloud Identity Platform.

Imparerai a utilizzare

  • Sostituisci l'utilizzo del servizio utenti di App Engine con Cloud Identity Platform
  • Sostituisci l'utilizzo di App Engine NDB con Cloud NDB (vedi anche il modulo 2)
  • Configura diversi provider di identità di autenticazione utilizzando Firebase Auth
  • Utilizza l'API Cloud Resource Manager per ottenere informazioni IAM del progetto
  • Utilizzare l'SDK Firebase Admin per ottenere informazioni sugli utenti
  • Porta l'applicazione di esempio su Python 3

Che cosa ti serve

Sondaggio

Come utilizzerai questo tutorial?

Solo lettura Lettura e completamento degli esercizi

Come valuteresti la tua esperienza con Python?

Principiante Intermedio Avanzato

Come valuti la tua esperienza di utilizzo dei servizi Google Cloud?

Principiante Intermedio Avanzato

2. Sfondo

Il servizio Users di App Engine è un sistema di autenticazione degli utenti da utilizzare per le app App Engine. Fornisce l'accesso con Google come provider di identità, link di accesso e disconnessione pratici da utilizzare nelle app e supporta il concetto di utenti amministratore e funzionalità solo per amministratori. Per migliorare la portabilità delle applicazioni, Google Cloud consiglia di eseguire la migrazione dai servizi integrati legacy di App Engine ai servizi autonomi di Cloud, ad esempio dal servizio Users a Cloud Identity Platform.

Identity Platform si basa su Firebase Authentication e aggiunge una serie di funzionalità enterprise, tra cui l'autenticazione a più fattori, il supporto SSO OIDC e SAML, il multitenancy, lo SLA del 99, 95% e altro ancora. Queste differenze sono evidenziate anche nella pagina di confronto dei prodotti Identity Platform e Firebase Authentication. Entrambi i prodotti hanno molte più funzionalità rispetto a quelle fornite dal servizio Utenti.

Questo codelab del modulo 21 mostra il passaggio dell'autenticazione utente dell'app dal servizio Utenti alle funzionalità di Identity Platform che rispecchiano più da vicino la funzionalità mostrata nel modulo 20. Il modulo 21 include anche una migrazione da App Engine NDB a Cloud NDB per l'accesso a Datastore, ripetendo la migrazione del modulo 2.

Sebbene il codice del modulo 20 sia "pubblicizzato" come app di esempio Python 2, l'origine stessa è compatibile con Python 2 e 3 e rimane tale anche dopo la migrazione a Identity Platform (e Cloud NDB) nel modulo 21. È possibile continuare a utilizzare il servizio Users durante l'upgrade a Python 3, poiché la migrazione a Identity Platform è facoltativa. Consulta il codelab del modulo 17 e il video per scoprire come continuare a utilizzare i servizi inclusi durante l'upgrade ai runtime di seconda generazione come Python 3.

Questo tutorial prevede i seguenti passaggi:

  1. Configurazione/preparazione
  2. Aggiorna configurazione
  3. Modificare il codice dell'applicazione

3. Configurazione/preparazione

Questa sezione spiega come:

  1. Configura il progetto cloud
  2. Ottieni l'app di esempio di base
  3. (R)esegui il deployment e convalida l'app di riferimento
  4. Abilitare nuovi servizi/API Google Cloud

Questi passaggi assicurano di iniziare con un codice funzionante pronto per la migrazione ai servizi Cloud autonomi.

1. Configura il progetto

Se hai completato il codelab del modulo 20, riutilizza lo stesso progetto (e codice). In alternativa, crea un nuovo progetto o riutilizza un altro progetto esistente. Assicurati che il progetto abbia un account di fatturazione attivo e un'app App Engine abilitata. Trova l'ID progetto e tienilo a portata di mano durante questo codelab e utilizzalo ogni volta che incontri la variabile PROJ_ID.

2. Ottieni l'app di esempio di base

Uno dei prerequisiti è un'app App Engine del modulo 20 funzionante, quindi completa il codelab (consigliato; link sopra) o copia il codice del modulo 20 dal repository. Che tu utilizzi il tuo o il nostro, è qui che inizieremo ("INIZIO"). Questo codelab ti guida nella migrazione e si conclude con un codice simile a quello presente nella cartella del repository del modulo 21 ("FINISH").

Copia la cartella del repository del modulo 20. Dovrebbe essere simile all'output riportato di seguito e potrebbe avere una cartella lib se hai seguito il codelab del modulo 20:

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

3. (R)esegui il deployment e convalida l'app di riferimento

Per eseguire il deployment dell'app Modulo 20:

  1. Elimina la cartella lib, se presente, ed esegui pip install -t lib -r requirements.txt per riempirla di nuovo. Potresti dover utilizzare pip2 se hai installato sia Python 2 che 3.
  2. Assicurati di aver installato e inizializzato lo strumento a riga di comando gcloud e di averne esaminato l'utilizzo.
  3. Se non vuoi inserire il tuo PROJ_ID con ogni comando gcloud emesso, imposta prima il progetto Cloud con gcloud config set project PROJ_ID.
  4. Esegui il deployment dell'app di esempio con gcloud app deploy
  5. Verifica che l'app funzioni come previsto senza errori. Se hai completato il codelab del modulo 20, l'app mostra le informazioni di accesso dell'utente (email dell'utente, eventuale "badge amministratore" e pulsante di accesso/disconnessione) in alto insieme alle visite più recenti (illustrate di seguito).

907e64c19ef964f8.png

L'accesso come utente normale comporta la visualizzazione dell'indirizzo email dell'utente e il pulsante "Accedi" diventa "Esci":

ad7b59916b69a035.png

L'accesso come utente amministratore comporta la visualizzazione dell'indirizzo email dell'utente insieme a "(amministratore)" accanto:

867bcb3334149e4.png

4. Abilitare nuovi servizi/API Google Cloud

Introduzione

L'app Modulo 20 utilizza le API NDB e Users di App Engine, servizi in bundle che non richiedono configurazione aggiuntiva, ma i servizi Cloud autonomi sì. L'app aggiornata utilizzerà sia Cloud Identity Platform sia Cloud Datastore (tramite la libreria client Cloud NDB). Inoltre, la nostra necessità di determinare gli utenti amministratore di App Engine richiede anche l'utilizzo dell'API Cloud Resource Manager.

Costo

  • App Engine e Cloud Datastore hanno quote del livello "Always Free" e, finché rispetti questi limiti, non dovresti incorrere in addebiti durante il completamento di questo tutorial. Per maggiori dettagli, consulta anche la pagina dei prezzi di App Engine e la pagina dei prezzi di Cloud Datastore.
  • L'utilizzo di Cloud Identity Platform viene fatturato in base al numero di utenti attivi mensili (MAU) o alle verifiche di autenticazione; per ogni modello di utilizzo è disponibile una versione "senza costi". Per ulteriori dettagli, consulta la pagina dei prezzi. Inoltre, mentre App Engine e Cloud Datastore richiedono la fatturazione, l'utilizzo di GCIP di per sé non richiede l'attivazione della fatturazione, a condizione che non vengano superate le quote giornaliere senza strumenti, quindi prendi in considerazione questa opzione per i progetti cloud che non prevedono API/servizi cloud che richiedono la fatturazione.
  • L'utilizzo dell'API Cloud Resource Manager è senza costi per la maggior parte dei casi, come indicato nella pagina dei prezzi.

Gli utenti abilitano le API Cloud dalla console Cloud o dalla riga di comando (tramite il comando gcloud, parte di Cloud SDK), a seconda delle preferenze. Iniziamo con le API Cloud Datastore e Cloud Resource Manager.

Dalla console Cloud

Vai alla pagina della libreria di API Manager (per il progetto corretto) in Cloud Console e cerca un'API utilizzando la barra di ricerca. c7a740304e9d35b.png

Abilita queste API:

Trova e fai clic sul pulsante Abilita per ogni API separatamente. Potrebbe esserti richiesto di inserire i dati di fatturazione. Ad esempio, ecco la pagina dell'API Resource Manager:

fc7bd8f4c49d12e5.png

Il pulsante diventa Gestisci quando è stato attivato (in genere dopo alcuni secondi):

8eca12d6cc7b45b0.png

Abilita Cloud Datastore nello stesso modo:

83811599b110e46b.png

Dalla riga di comando

Sebbene l'attivazione delle API dalla console sia visivamente informativa, alcuni utenti preferiscono la riga di comando. Inoltre, puoi abilitare contemporaneamente tutte le API che vuoi. Esegui questo comando per abilitare sia le API Cloud Datastore che Cloud Resource Manager e attendi il completamento dell'operazione, come illustrato di seguito:

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

Potrebbe esserti richiesto di inserire i dati di fatturazione.

Gli "URL" di ogni API utilizzata nel comando precedente sono chiamati nomi dei servizi API e si trovano in fondo alla pagina della libreria di ogni API. Se vuoi abilitare altre API Cloud per le tue app, puoi trovare i rispettivi nomi di servizio nelle pagine API corrispondenti. Questo comando elenca tutti i nomi dei servizi per le API che puoi abilitare:

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

Nella console Cloud o nella riga di comando, una volta completati i passaggi precedenti, il nostro esempio è ora in grado di accedere a queste API. I passaggi successivi consistono nell'attivare Cloud Identity Platform e apportare le modifiche necessarie al codice.

Attiva e configura Cloud Identity Platform (solo console Cloud)

Cloud Identity Platform è un servizio Marketplace perché si connette a una risorsa esterna a Google Cloud o dipende da questa, ad esempio Firebase Authentication. Al momento, puoi abilitare i servizi Marketplace solo dalla console Cloud. Procedi nel seguente modo:

  1. Vai alla pagina Cloud Identity Platform in Cloud Marketplace e fai clic sul pulsante Abilita. Esegui l'upgrade da Firebase Authentication se richiesto. In questo modo, sbloccherai funzionalità aggiuntive, come quelle descritte in precedenza nella sezione Background. Ecco la pagina del Marketplace che mette in evidenza il pulsante Attiva: 28475f1c9b29de69.png
  2. Una volta attivato Identity Platform, potresti essere indirizzato automaticamente alla pagina Provider di identità. In caso contrario, utilizza questo comodo link per accedere. fc2d92d42a5d1dd7.png
  3. Attiva il provider Google Auth. Se non è stato configurato alcun fornitore, fai clic su Aggiungi un fornitore e seleziona Google. Quando torni a questa schermata, la voce Google dovrebbe essere attiva. Google è l'unico fornitore di autenticazione che utilizziamo in questo tutorial per eseguire il mirroring del servizio App Engine Users come servizio Accedi con Google leggero. Nelle tue app, puoi attivare ulteriori provider di autenticazione.
  4. Dopo aver selezionato e configurato Google e gli altri provider di autenticazione che preferisci, fai clic su Dettagli configurazione applicazione e, nella finestra di dialogo che si apre, copia apiKey e authDomain nell'oggetto config nella scheda Web, salvandoli in un luogo sicuro. Perché non copiarlo tutto? Lo snippet in questa finestra di dialogo è hardcoded e datato, quindi salva solo le parti più importanti e utilizzale nel nostro codice con un utilizzo più simultaneo di Firebase Authentication. Dopo aver copiato i valori e averli salvati in un luogo sicuro, fai clic sul pulsante Chiudi per completare tutta la configurazione necessaria. bbb09dcdd9be538e.png

4. Aggiorna configurazione

Gli aggiornamenti alla configurazione includono sia la modifica di vari file di configurazione sia la creazione dell'equivalente di App Engine, ma all'interno dell'ecosistema Cloud Identity Platform.

appengine_config.py

  • Se esegui l'upgrade a Python 3, elimina appengine_config.py
  • Se prevedi di eseguire l'upgrade a Identity Platform, ma rimani su Python 2, non eliminare il file. Verrà aggiornato in un secondo momento durante il backporting di Python 2.

requirements.txt

Il file requirements.txt del modulo 20 elencava solo Flask. Per il modulo 21, aggiungi i seguenti pacchetti:

Il contenuto di requirements.txt ora dovrebbe essere simile al seguente:

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

app.yaml

  • L'aggiornamento a Python 3 comporta la semplificazione del file app.yaml. Rimuovi tutto tranne la direttiva runtime e impostala su una versione di Python 3 attualmente supportata. L'esempio utilizza attualmente la versione 3.10.
  • Se continui a utilizzare Python 2, non fare ancora nulla.

PRIMA:

runtime: python27
threadsafe: yes
api_version: 1

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

L'app di esempio del modulo 20 non dispone di gestori di file statici. Se le tue app lo fanno, lasciale intatte. Puoi rimuovere tutti i gestori di script, se vuoi, o lasciarli come riferimento, a condizione che modifichi i relativi handle in auto, come descritto nella guida alla migrazione di app.yaml. Con queste modifiche, l'app.yaml aggiornato per Python 3 è semplificato in:

DOPO:

runtime: python310

Altri aggiornamenti della configurazione

Se rimani su Python 2 o esegui il porting a Python 3, elimina la cartella lib.

5. Modificare il codice dell'applicazione

Questa sezione include aggiornamenti al file dell'applicazione principale, main.py, che sostituiscono l'utilizzo del servizio utenti App Engine con Cloud Identity Platform. Dopo aver aggiornato l'applicazione principale, aggiorna il modello web templates/index.html.

Aggiornare le importazioni e l'inizializzazione

Segui i passaggi riportati di seguito per aggiornare le importazioni e inizializzare le risorse dell'applicazione:

  1. Per le importazioni, sostituisci App Engine NDB con Cloud NDB.
  2. Oltre a Cloud NDB, importa anche Cloud Resource Manager.
  3. Identity Platform si basa su Firebase Auth, quindi importa l'SDK Firebase Admin.
  4. Le API Cloud richiedono l'utilizzo di un client API, quindi inizializzalo per Cloud NDB subito dopo l'inizializzazione di Flask.

Sebbene il pacchetto Cloud Resource Manager venga importato qui, lo utilizzeremo in una fase successiva dell'inizializzazione dell'app. Di seguito sono riportati le importazioni e l'inizializzazione del modulo 20, seguite da come dovrebbero apparire le sezioni dopo l'implementazione delle modifiche riportate sopra:

PRIMA:

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

app = Flask(__name__)

DOPO:

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

Assistenza per gli utenti amministratori di App Engine

Esistono due componenti da aggiungere all'app che supportano il riconoscimento degli utenti amministratori:

  • _get_gae_admins(): raccoglie un insieme di utenti amministratori; viene chiamato una volta e salvato
  • is_admin(): verifica se l'utente che ha eseguito l'accesso è un utente amministratore; viene chiamato a ogni accesso utente

La funzione di utilità _get_gae_admins() chiama l'API Resource Manager per recuperare l'allow-policy Cloud IAM corrente. La policy di autorizzazione definisce e applica i ruoli concessi alle entità (utenti umani, service account e così via). La configurazione include:

  • Recupero dell'ID progetto Cloud (PROJ_ID)
  • Creazione di un client API Resource Manager (rm_client)
  • Creazione di un insieme (di sola lettura) di ruoli di amministrazione di App Engine (_TARGETS)

Resource Manager richiede l'ID progetto cloud, quindi importa google.auth.default() e chiama questa funzione per ottenere l'ID progetto. Questa chiamata include un parametro che sembra un URL, ma è un ambito di autorizzazione OAuth2. Quando esegui app nel cloud, ad esempio su una VM Compute Engine o un'app App Engine, viene fornito un service account predefinito con privilegi ampi. In linea con la best practice dei privilegi minimi, ti consigliamo di creare i tuoi service account gestiti dall'utente.

Per le chiamate API, è consigliabile ridurre ulteriormente l'ambito delle tue app a un livello minimo necessario per funzionare correttamente. La chiamata API Resource Manager che effettueremo è get_iam_policy(), che richiede uno dei seguenti ambiti per funzionare:

  • 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

L'app di esempio richiede solo l'accesso in sola lettura alla policy di autorizzazione. Non modifica le norme e non ha bisogno dell'accesso all'intero progetto. Ciò significa che l'app non ha bisogno di nessuna delle prime tre autorizzazioni necessarie. L'ultima è l'unica richiesta e quella che stiamo implementando per l'app di esempio.

Il corpo principale della funzione crea un insieme vuoto di utenti amministratori (admins), recupera allow_policy tramite get_iam_policy() e scorre tutti i relativi binding alla ricerca specifica dei ruoli di amministratore App Engine:

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

Per ogni ruolo di destinazione trovato, raccoglie gli utenti che appartengono a quel ruolo e li aggiunge al set complessivo di utenti amministratore. Termina restituendo tutti gli utenti amministratore trovati e memorizzati nella cache come costante (_ADMINS) per la durata di questa istanza App Engine. Vedremo la chiamata a breve.

Aggiungi la seguente definizione di funzione _get_gae_admins() a main.py subito dopo l'istanza del client API Cloud NDB (ds_client):

def _get_gae_admins():
    'return set of App Engine admins'
    # setup constants for calling Cloud Resource Manager API
    _, PROJ_ID = default(  # Application Default Credentials and project ID
            ['https://www.googleapis.com/auth/cloudplatformprojects.readonly'])
    rm_client = resourcemanager.ProjectsClient()
    _TARGETS = frozenset((     # App Engine admin roles
            'roles/viewer',
            'roles/editor',
            'roles/owner',
            'roles/appengine.appAdmin',
    ))

    # collate users who are members of at least one GAE admin role (_TARGETS)
    admins = set()                      # set of all App Engine admins
    allow_policy = rm_client.get_iam_policy(resource='projects/%s' % PROJ_ID)
    for b in allow_policy.bindings:     # bindings in IAM allow-policy
        if b.role in _TARGETS:          # only look at GAE admin roles
            admins.update(user.split(':', 1).pop() for user in b.members)
    return admins

Quando gli utenti accedono all'app, si verifica quanto segue:

  1. Dopo che un utente ha eseguito l'accesso a Firebase, viene eseguito un rapido controllo dal modello web.
  2. Quando lo stato di autenticazione cambia nel modello, viene effettuata una chiamata fetch() in stile Ajax a /is_admin, il cui gestore è la funzione successiva, is_admin().
  3. Il token ID Firebase viene passato nel corpo POST a is_admin(), che lo estrae dalle intestazioni e chiama l'SDK Firebase Admin per convalidarlo. Se si tratta di un utente valido, estrai il suo indirizzo email e verifica se è un utente amministratore.
  4. Il risultato booleano viene quindi restituito al modello come 200 riuscito.

Aggiungi is_admin() a main.py subito dopo _get_gae_admins():

@app.route('/is_admin', methods=['POST'])
def is_admin():
    'check if user (via their Firebase ID token) is GAE admin (POST) handler'
    id_token = request.headers.get('Authorization')
    email = auth.verify_id_token(id_token).get('email')
    return {'admin': email in _ADMINS}, 200

Per replicare la funzionalità disponibile dal servizio Users, in particolare la funzione is_current_user_admin(), è necessario tutto il codice di entrambe le funzioni. Questa chiamata di funzione nel modulo 20 ha fatto tutto il lavoro pesante, a differenza del modulo 21 in cui implementiamo una soluzione sostitutiva. La buona notizia è che l'app non dipende più da un servizio solo App Engine, il che significa che puoi spostare le tue app su Cloud Run o altri servizi. Inoltre, puoi anche modificare la definizione di "utente amministratore" per le tue app semplicemente passando ai ruoli desiderati in _TARGETS, mentre il servizio Utenti è codificato in modo permanente per i ruoli di amministratore di App Engine.

Inizializza Firebase Auth e memorizza nella cache gli utenti amministratore di App Engine

Avremmo potuto inizializzare Firebase Auth in alto, vicino al punto in cui viene inizializzata l'app Flask e creato il client API Cloud NDB, ma non è stato necessario fino a quando non è stato definito tutto il codice di amministrazione, ovvero dove ci troviamo ora. Analogamente, ora che _get_gae_admins() è definito, chiamalo per memorizzare nella cache l'elenco degli utenti amministratori.

Aggiungi queste righe appena sotto il corpo della funzione di is_admin():

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

Visita la pagina Aggiornamenti del modello dati

Il modello di dati Visit non cambia. L'accesso a Datastore richiede l'utilizzo esplicito del gestore del contesto del client API Cloud NDB, ds_client.context(). Nel codice, ciò significa racchiudere le chiamate Datastore sia in store_visit() sia in fetch_visits() all'interno dei blocchi with di Python. Questo aggiornamento è identico al modulo 2. Apporta le modifiche nel seguente modo:

PRIMA:

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)

DOPO:

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)

Sposta la logica di accesso degli utenti nel modello web

Il servizio App Engine Users è lato server, mentre Firebase Auth e Cloud Identity Platform sono principalmente lato client. Di conseguenza, gran parte del codice di gestione degli utenti nell'app del modulo 20 viene spostato nel modello web del modulo 21.

In main.py, il contesto web passa cinque elementi essenziali di dati al modello. I primi quattro elencati sono legati alla gestione degli utenti e variano a seconda che l'utente abbia eseguito l'accesso o meno:

  • who: l'email dell'utente se ha eseguito l'accesso o user in caso contrario
  • admin: badge (amministratore) se l'utente che ha eseguito l'accesso è un amministratore
  • sign: mostra il pulsante Accedi o Esci
  • link: link di accesso o disconnessione al clic del pulsante
  • visits: visite più recenti

PRIMA:

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

Tutta la gestione degli utenti viene spostata nel modello web, quindi rimangono solo le visite, riportando il gestore principale a quello che avevamo nell'app del modulo 1:

DOPO:

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

Aggiorna modello web

Come appaiono nel modello tutti gli aggiornamenti della sezione precedente? Principalmente, la gestione degli utenti è stata spostata dall'app a Firebase Auth in esecuzione nel modello e una parte di tutto il codice è stata trasferita in JavaScript. Abbiamo notato una notevole riduzione di main.py, quindi prevediamo una crescita simile in templates/index.html.

PRIMA:

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

Sostituisci l'intero modello web con i contenuti riportati di seguito:

DOPO:

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

Il corpo HTML contiene molti componenti, quindi esaminiamoli uno alla volta.

Importazioni Firebase

Sempre nell'intestazione del documento HTML, dopo il titolo della pagina, importa i componenti Firebase necessari. Per una maggiore efficienza, i componenti di Firebase sono ora suddivisi in più moduli. Il codice per inizializzare Firebase viene importato dal modulo principale dell'app Firebase, mentre le funzioni che gestiscono Firebase Auth, Google come fornitore di autenticazione, l'accesso e la disconnessione e il "callback" della modifica dello stato di autenticazione vengono importati dal modulo 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";

Configurazione di Firebase

In precedenza, durante la parte di configurazione di Identity Platform di questo tutorial, hai salvato apiKey e authDomain dalla finestra di dialogo Dettagli di configurazione dell'applicazione. Aggiungi questi valori alla variabile firebaseConfig nella sezione successiva. Nei commenti è disponibile un link a istruzioni più dettagliate:

// 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",
};

Inizializzazione di Firebase

La sezione successiva inizializza Firebase con queste informazioni di configurazione.

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

In questo modo viene impostata la possibilità di utilizzare Google come provider di autenticazione e viene fornita un'opzione commentata per mostrare il selettore dell'account anche se è registrato un solo Account Google nella sessione del browser. In altre parole, quando hai più account, viene visualizzato il "selettore di account" come previsto: a38369389b7c4c7e.png Tuttavia, se nella sessione è presente un solo utente, la procedura di accesso viene completata automaticamente senza alcuna interazione dell'utente. Il popup viene visualizzato e poi scompare. Puoi forzare la visualizzazione della finestra di dialogo di selezione dell'account per un utente (anziché accedere immediatamente all'app) rimuovendo il commento dalla riga del parametro personalizzato. Se attivato, anche gli accessi per singolo utente visualizzano il selettore di account: b75624cb68d94557.png

Funzioni di accesso e disconnessione

Le righe di codice successive costituiscono le funzioni per i clic sui pulsanti di accesso o disconnessione:

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

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

Azioni di accesso e disconnessione

L'ultima sezione principale di questo blocco <script> è la funzione chiamata per ogni modifica dell'autenticazione (accesso o disconnessione).

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

Il codice nel modulo 20 che determina se inviare un contesto di modello "utente ha eseguito l'accesso" o un contesto "utente ha eseguito la disconnessione" viene trasferito qui. La condizione nella parte superiore restituisce true se l'utente ha eseguito l'accesso correttamente, attivando le seguenti azioni:

  1. L'indirizzo email dell'utente è impostato per la visualizzazione.
  2. Il pulsante Accedi cambia in Esci.
  3. Viene effettuata una chiamata in stile Ajax a /is_admin per determinare se mostrare il badge utente amministratore (admin).

Quando l'utente si disconnette, viene eseguita la clausola else per reimpostare tutte le informazioni utente:

  1. Nome utente impostato su user
  2. Qualsiasi badge amministratore rimosso
  3. Il pulsante Disconnetti è tornato a essere Accedi

Variabili del modello

Al termine della sezione dell'intestazione, il corpo principale inizia con le variabili del modello che vengono sostituite dagli elementi HTML che cambiano in base alle necessità:

  1. Nome utente visualizzato
  2. Badge amministratore (admin) (se applicabile)
  3. Pulsante Login (Accedi) o Logout (Disconnetti)
<body>
<p>
Welcome, <span id="who"></span> <span id="admin"><code>(admin)</code></span>
<button id="logbtn"></button>
</p><hr>

Variabili degli elementi HTML e delle visite più recenti

Il codice delle visite più recenti non cambia e l'ultimo blocco <script> imposta le variabili per gli elementi HTML che cambiano per l'accesso e la disconnessione elencati appena sopra:

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

Con questo si concludono le modifiche necessarie nel modello di applicazione e web per passare dalle API App Engine NDB e Users a Cloud NDB e Identity Platform, nonché l'upgrade a Python 3. Congratulazioni per aver raggiunto la nuova app di esempio del Modulo 21. La nostra versione è disponibile per la revisione nella cartella del repository del Modulo 21b.

La parte successiva del codelab è facoltativa (*) e solo per gli utenti le cui app devono rimanere su Python 2, guidandoti attraverso i passaggi necessari per arrivare a un'app Python 2 del modulo 21 funzionante.

6. *Backport di Python 2

Questa sezione facoltativa è destinata agli sviluppatori che eseguono una migrazione di Identity Platform, ma che devono continuare a essere eseguiti sul runtime Python 2. Se non ti preoccupa, salta questa sezione.

Per creare una versione funzionante in Python 2 dell'app Modulo 21, devi disporre di quanto segue:

  1. Requisiti di runtime: file di configurazione che supportano Python 2 e modifiche richieste nell'applicazione principale per evitare incompatibilità con Python 3
  2. Modifica secondaria della libreria:Python 2 è stato ritirato prima che alcune funzionalità richieste venissero aggiunte alla libreria client Resource Manager. Di conseguenza, hai bisogno di un modo alternativo per accedere a questa funzionalità mancante.

Eseguiamo questi passaggi ora, a partire dalla configurazione.

Ripristina appengine_config.py

In precedenza in questo tutorial, ti è stato chiesto di eliminare appengine_config.py perché non viene utilizzato dal runtime Python 3 App Engine. Per Python 2, non solo deve essere conservato, ma il modulo 20 appengine_config.py deve essere aggiornato per supportare l'uso di librerie di terze parti integrate, ovvero grpcio e setuptools. Questi pacchetti sono necessari ogni volta che l'app App Engine utilizza librerie client Cloud come quelle per Cloud NDB e Cloud Resource Manager.

Aggiungerai questi pacchetti a app.yaml tra poco, ma affinché la tua app possa accedervi, è necessario chiamare la funzione pkg_resources.working_set.add_entry() di setuptools. In questo modo, le librerie di terze parti copiate (autocompilate o vendute) installate nella cartella lib possono comunicare con le librerie integrate.

Implementa i seguenti aggiornamenti al file appengine_config.py per applicare queste modifiche:

PRIMA:

from google.appengine.ext import vendor

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

Questo codice da solo non è sufficiente per supportare l'utilizzo di setuptools e grpcio. Sono necessarie altre righe, quindi aggiorna appengine_config.py in modo che sia simile a questo:

DOPO:

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)

Per ulteriori dettagli sulle modifiche necessarie per supportare le librerie client Cloud, consulta la documentazione sulla migrazione dei servizi in bundle.

app.yaml

Analogamente a appengine_config.py, il file app.yaml deve essere ripristinato a una versione che supporti Python 2. Iniziamo con il modulo 20 originale app.yaml:

PRIMA:

runtime: python27
threadsafe: yes
api_version: 1

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

Oltre a setuptools e grpcio, come menzionato in precedenza, esiste una dipendenza (non esplicitamente correlata alla migrazione di Identity Platform) che richiede l'utilizzo della libreria client di Cloud Storage e che necessita di un altro pacchetto di terze parti integrato, ssl. Aggiungi tutti e tre in una nuova sezione libraries, selezionando le versioni "più recenti" disponibili di questi pacchetti, a app.yaml:

DOPO:

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

Per il modulo 21, abbiamo aggiunto Google Auth, Cloud NDB, Cloud Resource Manager e Firebase Admin SDK a Python 3 requirements.txt. La situazione per Python 2 è più complessa:

  • L'API Resource Manager fornisce la funzionalità allow-policy necessaria per l'app di esempio. Purtroppo questo supporto non era ancora disponibile nella versione finale di Python 2 della libreria client Cloud Resource Manager. È disponibile solo nella versione Python 3.
  • Di conseguenza, è necessario un modo alternativo per accedere a questa funzionalità dall'API. La soluzione consiste nell'utilizzare la libreria client delle API di Google di livello inferiore per comunicare con l'API. Per passare a questa libreria client, sostituisci google-cloud-resource-manager con il pacchetto google-api-python-client di livello inferiore.
  • Poiché Python 2 è stato ritirato, il grafico delle dipendenze che supporta il modulo 21 richiede il blocco di determinati pacchetti su versioni specifiche. Alcuni pacchetti devono essere richiamati anche se non sono specificati in Python 3 app.yaml.

PRIMA:

flask

A partire dal modulo 20 requirements.txt, aggiornalo come segue per un'app del modulo 21 funzionante:

DOPO:

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

I numeri di pacchetto e di versione verranno aggiornati nel repository man mano che le dipendenze cambiano, ma questo app.yaml è sufficiente per un'app funzionante al momento della stesura di questo articolo.

Altri aggiornamenti della configurazione

Se non hai eliminato la cartella lib in precedenza in questo codelab, fallo ora. Con requirements.txt appena aggiornato, esegui questo comando familiare per installare questi requisiti in lib:

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

Se hai installato sia Python 2 sia Python 3 sul tuo sistema di sviluppo, potresti dover utilizzare pip2 anziché pip.

Modificare il codice dell'applicazione

Fortunatamente, la maggior parte delle modifiche richieste si trova nei file di configurazione. L'unica modifica necessaria nel codice dell'applicazione è un aggiornamento minore per utilizzare la libreria client dell'API Google di livello inferiore anziché la libreria client Resource Manager per accedere all'API. Non sono necessari aggiornamenti al modello web templates/index.html.

Aggiorna importazioni e inizializzazione

Sostituisci la libreria client Resource Manager (google.cloud.resourcemanager) con la libreria client delle API di Google (googleapiclient.discovery), come illustrato di seguito:

PRIMA:

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

DOPO:

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

Assistenza per gli utenti amministratori di App Engine

Per supportare l'utilizzo della libreria client di livello inferiore, sono necessarie alcune modifiche in _get_gae_admins(). Vediamo prima cosa cambierà e poi ti forniremo tutto il codice da aggiornare.

Il codice Python 2 richiede l'utilizzo sia delle credenziali che dell'ID progetto restituiti da google.auth.default(). Le credenziali non vengono utilizzate in Python 3, pertanto sono state assegnate a una variabile fittizia generica di sottolineatura ( _). Poiché è necessario per la versione Python 2, modifica il carattere di sottolineatura in CREDS. Inoltre, anziché creare un client API Resource Manager, creerai un endpoint di servizio API, simile per concetto a un client API, quindi manteniamo lo stesso nome di variabile (rm_client). Una differenza è che l'istanza di un endpoint di servizio richiede credenziali (CREDS).

Queste modifiche sono riportate nel codice seguente:

PRIMA:

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

DOPO:

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)

L'altra differenza è che la libreria client Resource Manager restituisce oggetti allow-policy che utilizzano la notazione degli attributi con punti, mentre la libreria client di livello inferiore restituisce dizionari Python in cui vengono utilizzate le parentesi quadre ( [ ] ). Ad esempio, utilizza binding.role per la libreria client Resource Manager e binding['role'] per la libreria di livello inferiore. La prima utilizza anche nomi "separati_da_trattini_bassi" rispetto alla libreria di livello inferiore che preferisce nomi "CamelCase" e un modo leggermente diverso di passare i parametri API.

Queste differenze di utilizzo sono mostrate di seguito:

PRIMA:

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)

DOPO:

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

Mettendo insieme tutte queste modifiche, sostituisci _get_gae_admins() di Python 3 con questa versione equivalente di 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

La funzione is_admin() non richiede aggiornamenti perché si basa su _get_gae_admins(), che è già stato aggiornato.

Con questo si concludono le modifiche necessarie per eseguire il backporting dell'app del modulo 21 di Python 3 a Python 2. Congratulazioni per aver raggiunto l'app di esempio del Modulo 21 aggiornato. Tutto il codice è disponibile nella cartella del repository del modulo 21a.

7. Riepilogo/Pulizia

Gli ultimi passaggi del codelab consistono nell'assicurarsi che le entità (utenti o service account) che eseguono questa app dispongano delle autorizzazioni appropriate per farlo, quindi di eseguire il deployment dell'app per verificare che funzioni come previsto e che le modifiche vengano riflesse nell'output.

Possibilità di leggere il criterio di autorizzazione IAM

In precedenza, ti abbiamo presentato i quattro ruoli necessari per essere riconosciuto come utente amministratore di App Engine, ma ora ce n'è un quinto da conoscere:

  • roles/viewer
  • roles/editor
  • roles/owner
  • roles/appengine.appAdmin
  • roles/resourcemanager.projectIamAdmin (per le entità che accedono alla policy IAM allow)

Il ruolo roles/resourcemanager.projectIamAdmin consente alle entità di servizio di determinare se un utente finale è membro di uno dei ruoli di amministratore di App Engine. Senza l'appartenenza a roles/resourcemanager.projectIamAdmin, le chiamate all'API Cloud Resource Manager per ottenere la policy di autorizzazione non andranno a buon fine.

Non devi intraprendere alcuna azione esplicita qui, poiché la tua app verrà eseguita con il service account predefinito di App Engine, a cui viene concessa automaticamente l'appartenenza a questo ruolo. Anche se utilizzi il service account predefinito durante la fase di sviluppo, ti consigliamo vivamente di creare e utilizzare un service account gestito dall'utente con le autorizzazioni minime richieste per il corretto funzionamento della tua app. Per concedere l'appartenenza a un service account, esegui questo comando:

$ 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 è l'ID progetto Cloud e USR_MGD_SVC_ACCT@PROJ_ID.iam.gserviceaccount.com è il service account gestito dall'utente che crei per la tua app. Questo comando restituisce i criteri IAM aggiornati per il tuo progetto, in cui puoi verificare che il service account sia membro di roles/resourcemanager.projectIamAdmin. Per saperne di più, consulta la documentazione di riferimento. Ripeto, non devi eseguire questo comando in questo codelab, ma salvalo come riferimento per modernizzare le tue app.

Esegui il deployment e verifica l'applicazione

Carica la tua app sul cloud con il comando standard gcloud app deploy. Una volta eseguito il deployment, dovresti notare una funzionalità quasi identica a quella dell'app del modulo 20, tranne per il fatto che hai sostituito correttamente il servizio App Engine Users con Cloud Identity Platform (e Firebase Auth) per la gestione degli utenti:

3a83ae745121d70.png

Una differenza che noterai rispetto al modulo 20 è che il clic su Accedi genera un popup anziché un reindirizzamento, come mostrato in alcuni degli screenshot riportati di seguito. Come nel modulo 20, tuttavia, il comportamento varia leggermente a seconda del numero di Account Google registrati nel browser.

Se non sono registrati utenti con il browser o se è presente un solo utente che non ha ancora eseguito l'accesso, viene visualizzato un popup di accesso con Google generico:

8437f5f3d489a942.png

Se un singolo utente è registrato nel browser, ma esegue l'accesso altrove, non viene visualizzata alcuna finestra di dialogo (o viene visualizzata e chiusa immediatamente) e l'app passa allo stato di accesso (visualizza l'email dell'utente e il pulsante Esci).

Alcuni sviluppatori potrebbero voler fornire un selettore di account, anche per un singolo utente:

b75624cb68d94557.png

Per implementare questa funzionalità, rimuovi il commento dalla riga provider.setCustomParameters({prompt: 'select_account'}); nel modello web come descritto in precedenza.

Se ci sono più utenti, viene visualizzata la finestra di dialogo di selezione dell'account (vedi sotto). Se non ha ancora eseguito l'accesso, all'utente verrà chiesto di farlo. Se hai già eseguito l'accesso, il popup scompare e l'app passa allo stato di accesso eseguito.

c454455b6020d5e4.png

Lo stato di accesso del modulo 21 è identico all'interfaccia utente del modulo 20:

49ebe4dcc1eff11f.png

Lo stesso vale per l'accesso di un utente amministratore:

44302f35b39856eb.png

A differenza del modulo 21, il modulo 20 accede sempre alla logica per i contenuti del modello web dall'app (codice lato server). Un difetto del modulo 20 è che una visita viene registrata quando l'utente finale accede all'app per la prima volta e un'altra quando l'utente esegue l'accesso.

Per il modulo 21, la logica di accesso si svolge solo nel modello web (codice lato client). Non è necessario alcun viaggio lato server per determinare quali contenuti visualizzare. L'unica chiamata effettuata al server è il controllo degli utenti amministratore dopo l'accesso di un utente finale. Ciò significa che gli accessi e le disconnessioni non registrano visite aggiuntive, quindi l'elenco delle visite più recenti rimane costante per le azioni di gestione degli utenti. Nota che gli screenshot riportati sopra mostrano lo stesso insieme di quattro visite in più accessi utente.

Gli screenshot del modulo 20 mostrano il "bug della doppia visita" all'inizio di questo codelab. Per ogni azione di accesso o disconnessione vengono visualizzati log delle visite separati. Controlla i timestamp dell'ultima visita per ogni screenshot che mostra l'ordine cronologico.

Esegui la pulizia

Generale

Se hai finito per il momento, ti consigliamo di disattivare l'app App Engine per evitare addebiti. Tuttavia, se vuoi fare altri test o esperimenti, la piattaforma App Engine ha una quota senza costi e, finché non superi questo livello di utilizzo, non ti verranno addebitati costi. Questo vale per il calcolo, ma potrebbero essere addebitati anche costi per i servizi App Engine pertinenti, quindi consulta la pagina dei prezzi per ulteriori informazioni. Se questa migrazione coinvolge altri servizi cloud, questi vengono fatturati separatamente. In entrambi i casi, se applicabile, consulta la sezione "Specifiche per questo codelab" di seguito.

Per una divulgazione completa, il deployment su una piattaforma di calcolo serverless di Google Cloud come App Engine comporta costi di build e archiviazione minimi. Cloud Build ha una propria quota senza costi, così come Cloud Storage. L'archiviazione di questa immagine utilizza parte della quota. Tuttavia, potresti vivere in una regione che non dispone di un livello senza costi, quindi tieni sotto controllo l'utilizzo dello spazio di archiviazione per ridurre al minimo i potenziali costi. Le "cartelle" Cloud Storage specifiche che devi esaminare includono:

  • 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
  • I link di archiviazione riportati sopra dipendono dal tuo PROJECT_ID e dalla tua LOC, ad esempio "us" se la tua app è ospitata negli Stati Uniti.

D'altra parte, se non intendi continuare con questa applicazione o con altri codelab di migrazione correlati e vuoi eliminare tutto completamente, chiudi il progetto.

Specifico per questo codelab

I servizi elencati di seguito sono univoci per questo codelab. Per saperne di più, consulta la documentazione di ogni prodotto:

  • Il servizio App Engine Datastore è fornito da Cloud Datastore (Cloud Firestore in modalità Datastore), che dispone anche di un livello senza costi. Per ulteriori informazioni, consulta la pagina dei prezzi.
  • L'utilizzo della piattaforma Cloud Identity prevede un certo livello di "gratuità", a seconda dei servizi utilizzati. Per ulteriori dettagli, consulta la pagina dei prezzi.
  • L'utilizzo dell'API Cloud Resource Manager è senza costi per la maggior parte dei casi, come indicato nella pagina dei prezzi.

Passaggi successivi

Oltre a questo tutorial, altri moduli di migrazione che si concentrano sul passaggio dai servizi in bundle legacy da prendere in considerazione includono:

  • Modulo 2: esegui la migrazione da App Engine ndb a Cloud NDB
  • Moduli 7-9: esegui la migrazione da App Engine Task Queue (attività push) a Cloud Tasks
  • Moduli 12-13: esegui la migrazione da Memcache App Engine a Cloud Memorystore
  • Moduli 15-16: esegui la migrazione da App Engine Blobstore a Cloud Storage
  • Moduli 18-19: esegui la migrazione dalla coda di attività App Engine (attività pull) a Cloud Pub/Sub

App Engine non è più l'unica piattaforma serverless in Google Cloud. Se hai una piccola app App Engine o una con funzionalità limitate e vuoi trasformarla in un microservizio autonomo oppure vuoi suddividere un'app monolitica in più componenti riutilizzabili, questi sono buoni motivi per prendere in considerazione il passaggio a Cloud Functions. Se la containerizzazione è diventata parte del flusso di lavoro di sviluppo delle applicazioni, in particolare se consiste in una pipeline CI/CD (integrazione continua/distribuzione continua o deployment continuo), valuta la migrazione a Cloud Run. Questi scenari sono trattati nei seguenti moduli:

  • Esegui la migrazione da App Engine a Cloud Functions: consulta il modulo 11
  • Esegui la migrazione da App Engine a Cloud Run: consulta il modulo 4 per inserire la tua app in un container con Docker o il modulo 5 per farlo senza container, conoscenze di Docker o Dockerfiles

Il passaggio a un'altra piattaforma serverless è facoltativo e ti consigliamo di valutare le opzioni migliori per le tue app e i tuoi casi d'uso prima di apportare modifiche.

Indipendentemente dal modulo di migrazione che prenderai in considerazione, tutti i contenuti di Serverless Migration Station (codelab, video, codice sorgente [se disponibile]) sono accessibili nel relativo repository open source. Il repository README fornisce anche indicazioni sulle migrazioni da prendere in considerazione e sull'eventuale "ordine" dei moduli di migrazione pertinenti.

8. Risorse aggiuntive

Di seguito sono elencate risorse aggiuntive per gli sviluppatori che esplorano ulteriormente questo o altri moduli di migrazione correlati. Di seguito puoi fornire un feedback su questi contenuti, trovare link al codice e vari documenti che potrebbero esserti utili.

Problemi/feedback relativi a Codelab

Se riscontri problemi con questo codelab, cerca prima il tuo problema prima di presentare una segnalazione. Link per cercare e creare nuovi problemi:

Risorse per la migrazione

I link alle cartelle del repository per il modulo 20 (INIZIO) e il modulo 21 (FINE) sono disponibili nella tabella riportata di seguito.

Codelab

Python 2

Python 3

Modulo 20

code

(n/a)

Modulo 21 (questo codelab)

code

code

Riferimenti online

Di seguito sono riportate le risorse pertinenti per questo tutorial:

Cloud Identity Platform e Cloud Marketplace

Cloud Resource Manager, Cloud IAM, SDK Firebase Admin

Utenti App Engine, App Engine NDB, Cloud NDB, Cloud Datastore

Altri riferimenti al modulo di migrazione

Migrazione di App Engine

Piattaforma App Engine

Cloud SDK

Altre informazioni sul cloud

Video

Licenza

Questo lavoro è concesso in licenza ai sensi di una licenza Creative Commons Attribution 2.0 Generic.