Migrer du service Users d'App Engine vers Cloud Identity Platform (module 21)

1. Présentation

La série d'ateliers de programmation sur la station de migration sans serveur (tutoriels pratiques et d'auto-formation) et les vidéos associées visent à aider les développeurs sans serveur Google Cloud à moderniser leurs applications en les guidant dans une ou plusieurs migrations, principalement en abandonnant les anciens services. Vous améliorez ainsi la portabilité de vos applications, et vous bénéficiez de plus d'options et de flexibilité. Vous pouvez ainsi intégrer un plus large éventail de produits Cloud et y accéder, et passer plus facilement à de nouvelles langues. Bien qu'elle s'adresse initialement aux utilisateurs les plus anciens du cloud, principalement les développeurs d'environnements App Engine (standard), cette série est suffisamment large pour inclure d'autres plates-formes sans serveur telles que Cloud Functions et Cloud Run, ou ailleurs, le cas échéant.

L'objectif de cet atelier de programmation est de montrer aux développeurs Python 2 App Engine comment migrer de l'API/Service App Engine Users vers Cloud Identity Platform (GCIP). Il existe également une migration implicite d'App Engine NDB vers Cloud NDB pour l'accès à Datastore (principalement abordée dans le module de migration 2) ainsi qu'une mise à niveau vers Python 3.

Le module 20 explique comment ajouter l'utilisation de l'API Users à l'application exemple du module 1. Dans ce module, vous allez utiliser l'application du module 20 et migrer son utilisation vers Cloud Identity Platform.

Vous apprendrez à

  • Remplacer l'utilisation du service Users d'App Engine par Cloud Identity Platform
  • Remplacez l'utilisation d'App Engine NDB par Cloud NDB (consultez également le module 2).
  • Configurer différents fournisseurs d'identité pour l'authentification à l'aide de Firebase Auth
  • Utiliser l'API Cloud Resource Manager pour obtenir les informations IAM du projet
  • Utiliser le SDK Admin Firebase pour obtenir des informations sur les utilisateurs
  • Porter l'exemple d'application vers Python 3

Prérequis

Enquête

Comment allez-vous utiliser ce tutoriel ?

<ph type="x-smartling-placeholder"></ph> Je vous invite à le lire uniquement Je vais le lire et effectuer les exercices

Quel est votre niveau d'expérience avec Python ?

Débutant Intermédiaire Expert

Quel est votre niveau d'expérience avec les services Google Cloud ?

<ph type="x-smartling-placeholder"></ph> Débutant Intermédiaire Expert
.

2. Contexte

Le service Users d'App Engine est un système d'authentification des utilisateurs destiné aux applications App Engine. Il propose Google Sign-In comme fournisseur d'identité, fournit des liens pratiques de connexion et de déconnexion à utiliser dans les applications, et prend en charge le concept d'administrateurs et de fonctionnalités réservées aux administrateurs. Pour améliorer la portabilité des applications, Google Cloud recommande, entre autres, de migrer des anciens services groupés App Engine vers des services Cloud autonomes. Par exemple, du service Utilisateurs vers la plate-forme Cloud Identity.

Basé sur Firebase Authentication, Identity Platform ajoute de nombreuses fonctionnalités d'entreprise telles que l'authentification multifacteur, OIDC et Compatibilité avec l'authentification unique SAML, l'architecture mutualisée, le contrat de niveau de service garantissant une disponibilité de 99,95 %, et bien plus encore. Ces différences sont également mises en évidence sur la page de comparaison des produits Identity Platform et Firebase Authentication. Ces deux produits proposent des fonctionnalités beaucoup plus nombreuses que celles fournies par le service Utilisateurs.

Dans cet atelier de programmation du module 21, vous allez découvrir comment faire passer l'authentification utilisateur de l'application du service Users aux fonctionnalités Identity Platform qui se rapprochent le plus de celles présentées dans le module 20. Le module 21 propose également une migration d'App Engine NDB vers Cloud NDB pour l'accès à Datastore, en répétant la migration du module 2.

Alors que le code du module 20 est "annoncé" en tant qu'application exemple Python 2, la source elle-même est compatible avec Python 2 et 3, et elle le reste même après la migration vers Identity Platform (et Cloud NDB) dans le module 21. Il est possible de continuer à utiliser le service Users pendant la mise à niveau vers Python 3, car la migration vers Identity Platform est facultative. Consultez l'atelier de programmation du module 17 et la vidéo pour savoir comment continuer à utiliser les services groupés tout en passant à des environnements d'exécution de 2e génération tels que Python 3.

Ce tutoriel comprend les étapes suivantes:

  1. Configuration/Préparation
  2. Mettre à jour la configuration
  3. Modifier le code d'application

3. Configuration/Préparation

Cette section explique comment effectuer les opérations suivantes :

  1. Configurer votre projet Cloud
  2. Obtenir un exemple d'application de référence
  3. (Re)Déployer et valider l'application de référence
  4. Activer de nouveaux services/API Google Cloud

Cette procédure permet de s'assurer que vous commencez avec du code opérationnel, prêt pour la migration vers des services Cloud autonomes.

1. Configurer le projet

Si vous avez terminé l'atelier de programmation du module 20, réutilisez ce projet (et ce même code). Vous pouvez également créer un projet ou réutiliser un autre projet existant. Assurez-vous que le projet dispose d'un compte de facturation actif et d'une application App Engine activée. Recherchez l'ID de votre projet et gardez-le à portée de main au cours de cet atelier de programmation. Vous pourrez l'utiliser chaque fois que vous rencontrerez la variable PROJ_ID.

2. Obtenir un exemple d'application de référence

L'une des conditions préalables est une application App Engine opérationnelle du module 20. Vous devez donc suivre son atelier de programmation (recommandé ; lien ci-dessus) ou copier le code du module 20 à partir du dépôt. Que vous utilisiez la vôtre ou la nôtre, c'est ici que nous allons commencer ("DÉMARRER"). Cet atelier de programmation vous guide tout au long de la migration et se termine par un code ressemblant à celui du dossier du dépôt du module 21 ("FINISH").

Copiez le dossier du dépôt du module 20. Il doit ressembler à la sortie ci-dessous et peut contenir un dossier lib si vous avez suivi l'atelier de programmation du module 20:

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

3. (Re)Déployer et valider l'application de référence

Exécutez les étapes suivantes pour déployer l'application du module 20:

  1. Supprimez le dossier lib s'il y en a un, puis exécutez pip install -t lib -r requirements.txt pour le remplir à nouveau. Si Python 2 et 3 sont tous deux installés, vous devrez peut-être utiliser pip2.
  2. Assurez-vous d'avoir installé et initialisé l'outil de ligne de commande gcloud, et vérifié son utilisation.
  3. Si vous ne souhaitez pas saisir votre PROJ_ID avec chaque commande gcloud émise, définissez d'abord le projet Cloud avec gcloud config set project PROJ_ID.
  4. Déployer l'exemple d'application avec gcloud app deploy
  5. Vérifiez que l'application s'exécute comme prévu et sans erreur. Si vous avez terminé l'atelier de programmation du module 20, l'application affiche les informations de connexion des utilisateurs (adresse e-mail de l'utilisateur, badge d'administrateur possible et bouton de connexion/déconnexion) en haut de l'écran, avec les visites les plus récentes (illustrées ci-dessous).

907e64c19ef964f8.png

Si vous vous connectez en tant qu'utilisateur standard, l'adresse e-mail de l'utilisateur s'affiche et le bouton "Login" (Connexion) devient "Déconnexion" bouton:

ad7b59916b69a035.png

Si vous vous connectez en tant qu'administrateur, son adresse e-mail s'affiche avec la mention "(admin)" à côté:

867bcb3334149e4.png

4. Activer de nouveaux services/API Google Cloud

Introduction

L'application du module 20 utilise les API App Engine NDB et Users, des services groupés qui ne nécessitent pas de configuration supplémentaire, contrairement aux services Cloud autonomes. L'application mise à jour utilisera à la fois Cloud Identity Platform et Cloud Datastore (via la bibliothèque cliente Cloud NDB). De plus, pour déterminer les administrateurs d'App Engine, nous avons besoin de l'API Cloud Resource Manager.

Coût

  • App Engine et Cloud Datastore proposent le niveau "Toujours sans frais" de niveau supérieur, et tant que vous ne dépassez pas ces limites, aucuns frais ne devraient vous être facturés pour suivre ce tutoriel. Pour en savoir plus, consultez également les pages Tarifs d'App Engine et Tarifs de Cloud Datastore.
  • L'utilisation de Cloud Identity Platform est facturée en fonction du nombre d'utilisateurs actifs par mois (UAM) ou de vérifications de l'authentification. une version du mot "sans frais" est disponible pour chaque modèle d'utilisation. Consultez sa page des tarifs pour en savoir plus. De plus, bien qu'App Engine et Cloud Datastore requièrent une facturation, l'utilisation de GCIP en elle-même ne nécessite pas d'activer la facturation tant que vous ne dépassez pas ses quotas quotidiens sans instrument. Pensez-y pour les projets Cloud qui n'impliquent pas d'API/services Cloud nécessitant une facturation.
  • L'utilisation de l'API Cloud Resource Manager est sans frais dans la plupart des cas, conformément à sa page de tarification.

Les utilisateurs activent les API Cloud à partir de la console Cloud ou de la ligne de commande (via la commande gcloud, qui fait partie du SDK Cloud), selon vos préférences. Commençons par les API Cloud Datastore et Cloud Resource Manager.

Depuis Cloud Console

Accédez à la page Bibliothèque du gestionnaire d'API (du projet approprié) dans la console Cloud, puis recherchez une API à l'aide de la barre de recherche. c7a740304e9d35b.png

Activez les API suivantes:

Cliquez sur le bouton Activer pour chaque API. Vous serez peut-être invité à saisir vos informations de facturation. Par exemple, voici la page de l'API Resource Manager:

fc7bd8f4c49d12e5.png

Une fois activé, le bouton devient "Gérer" (généralement au bout de quelques secondes):

8eca12d6cc7b45b0.png

Activez Cloud Datastore de la même manière:

83811599b110e46b.png

Depuis la ligne de commande

Bien qu'il soit visuellement instructif d'activer des API à partir de la console, certains préfèrent la ligne de commande. De plus, vous pouvez activer autant d'API que vous le souhaitez en même temps. Exécutez cette commande pour activer les API Cloud Datastore et Cloud Resource Manager, puis attendez la fin de l'opération, comme illustré ci-dessous:

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

Vous serez peut-être invité à saisir vos informations de facturation.

La colonne "URL" des API utilisées dans la commande ci-dessus sont appelés noms de service d'API. Vous les trouverez au bas de la page de la bibliothèque de chaque API. Si vous souhaitez activer d'autres API Cloud pour vos propres applications, vous trouverez le nom de leurs services respectifs sur les pages d'API correspondantes. Cette commande liste tous les noms de service pour les API que vous pouvez activer:

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

Que ce soit dans la console Cloud ou sur la ligne de commande, une fois la procédure ci-dessus terminée, notre exemple peut désormais accéder à ces API. Les étapes suivantes consistent à activer la plate-forme Cloud Identity et à apporter les modifications de code nécessaires.

Activer et configurer Cloud Identity Platform (console Cloud uniquement)

Cloud Identity Platform est un service Marketplace, car il se connecte à une ressource externe à Google Cloud, telle que Firebase Authentication ou dépend d'une ressource externe à cette dernière. Pour le moment, vous ne pouvez activer les services Marketplace qu'à partir de la console Cloud. Procédez comme suit :

  1. Accédez à la page Cloud Identity Platform dans Cloud Marketplace, puis cliquez sur le bouton Activer. Effectuez la mise à niveau à partir de Firebase Authentication si vous y êtes invité. Cette action débloque des fonctionnalités supplémentaires, telles que celles décrites précédemment dans la section Arrière-plan. Voici la page "Place de marché" où le bouton Activer est mis en évidence: 28475f1c9b29de69.png
  2. Une fois qu'Identity Platform est activé, vous pouvez être automatiquement redirigé vers la page Fournisseurs d'identité. Si ce n'est pas le cas, cliquez sur ce lien pratique pour y accéder. fc2d92d42a5d1dd7.png
  3. Activer le fournisseur Google Auth. Si aucun fournisseur n'a été configuré, cliquez sur Ajouter un fournisseur, puis sélectionnez Google. Lorsque vous revenez à cet écran, l'entrée Google doit être activée. Google est le seul fournisseur d'authentification que nous utilisons dans ce tutoriel pour dupliquer le service Users d'App Engine sous la forme d'un service Google Sign-In léger. Dans vos propres applications, vous pouvez activer d'autres fournisseurs d'authentification.
  4. Après avoir sélectionné et configuré Google et les autres fournisseurs d'authentification souhaités, cliquez sur Application Setup Details (Détails de la configuration de l'application) et, dans la boîte de dialogue correspondante, copiez apiKey et authDomain dans l'objet config de l'onglet Web, en les enregistrant tous les deux en lieu sûr. Pourquoi ne pas tout copier ? L'extrait de cette boîte de dialogue est codé en dur et daté. Il vous suffit donc d'enregistrer les bits les plus importants et de les utiliser dans notre code avec davantage d'utilisation simultanée de Firebase Auth. Une fois les valeurs copiées et enregistrées en lieu sûr, cliquez sur le bouton Fermer pour terminer la configuration. bbb09dcdd9be538e.png

4. Mettre à jour la configuration

Les mises à jour de la configuration incluent la modification de différents fichiers de configuration et la création d'un équivalent d'App Engine, mais au sein de l'écosystème Cloud Identity Platform.

appengine_config.py

  • Si vous passez à Python 3, supprimez appengine_config.py
  • Si vous envisagez de passer à Identity Platform, mais que vous restez sur Python 2, ne supprimez pas le fichier. Nous le mettrons à jour plus tard lors du rétroportage de Python 2.

requirements.txt

Le fichier requirements.txt du module 20 n'indiquait que Flask. Pour le module 21, ajoutez les packages suivants:

Le contenu de requirements.txt devrait maintenant se présenter comme suit:

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

app.yaml

  • La mise à niveau vers Python 3 implique de simplifier le fichier app.yaml. Supprimez tout, à l'exception de la directive d'exécution, et définissez-la sur une version de Python 3 actuellement compatible. L'exemple utilise actuellement la version 3.10.
  • Si vous utilisez Python 2, aucune action n'est requise de votre part pour le moment.

AVANT:

runtime: python27
threadsafe: yes
api_version: 1

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

L'application exemple du module 20 ne comporte pas de gestionnaires de fichiers statiques. Si vos applications le sont, ne les modifiez pas. Vous pouvez supprimer tous vos gestionnaires de scripts si vous le souhaitez ou les laisser ici pour référence, à condition de remplacer leurs identifiants par auto, comme décrit dans le guide de migration app.yaml. Avec ces modifications, le app.yaml mis à jour pour Python 3 est simplifié en:

APRÈS:

runtime: python310

Autres mises à jour de configuration

Que vous restiez sur Python 2 ou que vous portiez sur Python 3, supprimez-le si vous avez un dossier lib.

5. Modifier le code d'application

Cette section présente les mises à jour du fichier d'application principal, main.py, qui remplace l'utilisation du service Users d'App Engine par la plate-forme Cloud Identity. Après avoir mis à jour l'application principale, vous mettrez à jour le modèle Web, templates/index.html.

Mettre à jour les importations et l'initialisation

Suivez les étapes ci-dessous pour mettre à jour les importations et initialiser les ressources de l'application:

  1. Pour les importations, remplacez App Engine NDB par Cloud NDB.
  2. Importez Cloud Resource Manager en plus de Cloud NDB.
  3. Comme Identity Platform est basé sur Firebase Auth, vous devez importer le SDK Firebase Admin.
  4. Les API Cloud nécessitent l'utilisation d'un client API. Vous devez donc le lancer pour Cloud NDB juste en dessous de l'initialisation de Flask.

Bien que le package Cloud Resource Manager soit importé ici, nous l'utiliserons ultérieurement lors de l'initialisation de l'application. Vous trouverez ci-dessous les importations et l'initialisation du module 20, puis la façon dont les sections doivent se présenter après la mise en œuvre des modifications ci-dessus:

AVANT:

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

app = Flask(__name__)

APRÈS:

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

Assistance pour les administrateurs App Engine

Vous devez ajouter deux composants à l'application pour permettre la reconnaissance des administrateurs:

  • _get_gae_admins() : rassemble l'ensemble des administrateurs ; appelé une fois et enregistré
  • is_admin() : vérifie si l'utilisateur connecté est un administrateur. appelé à n'importe quelle connexion utilisateur

La fonction utilitaire _get_gae_admins() appelle l'API Resource Manager pour récupérer la valeur allow-policy de Cloud IAM actuelle. La règle d'autorisation définit et applique les rôles attribués à quels comptes principaux (utilisateurs humains, comptes de service, etc.). La configuration comprend les étapes suivantes:

  • Récupération de l'ID du projet Cloud (PROJ_ID)...
  • Création d'un client API Resource Manager (rm_client)
  • Créer un ensemble (en lecture seule) de rôles d'administrateur App Engine (_TARGETS)

Resource Manager nécessite l'ID du projet Cloud. Importez donc google.auth.default() et appelez cette fonction pour obtenir l'ID du projet. Cet appel inclut un paramètre qui ressemble à une URL, mais qui a un champ d'application d'autorisation OAuth2. Lorsque vous exécutez des applications dans le cloud, par exemple sur une VM Compute Engine ou une application App Engine, un compte de service par défaut doté de privilèges étendus est fourni. Conformément à la bonne pratique du moindre privilège, nous vous recommandons de créer vos propres comptes de service gérés par l'utilisateur.

Pour les appels d'API, il est préférable de réduire davantage le champ d'application de vos applications au niveau minimal requis pour fonctionner correctement. L'appel d'API Resource Manager que nous allons effectuer est get_iam_policy(). Il nécessite l'un des champs d'application suivants pour fonctionner:

  • 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'application exemple n'a besoin que d'un accès en lecture seule à la règle allow-policy. Elle ne modifie pas la stratégie et n'a pas besoin d'accéder à l'ensemble du projet. Cela signifie que l'application n'a besoin d'aucune des trois premières autorisations requises. Le dernier élément est tout ce qui est requis. C'est celui que nous implémentons pour l'application exemple.

Le corps principal de la fonction crée un ensemble vide d'administrateurs (admins), récupère le allow_policy via get_iam_policy() et parcourt toutes ses liaisons en recherchant spécifiquement des rôles d'administrateur App Engine:

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

Pour chaque rôle cible trouvé, il classe les utilisateurs associés à ce rôle et les ajoute à l'ensemble des administrateurs. Elle se termine par le renvoi de tous les administrateurs trouvés et mis en cache sous forme de constante (_ADMINS) pendant toute la durée de vie de cette instance App Engine. Cet appel va bientôt arriver.

Ajoutez la définition de la fonction _get_gae_admins() suivante à main.py juste en dessous de l'instanciation du 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

Voici ce qui se produit lorsque les utilisateurs se connectent à l'application:

  1. Une vérification rapide est effectuée à partir du modèle Web une fois qu'un utilisateur s'est connecté à Firebase.
  2. Lorsque l'état d'authentification change dans le modèle, un appel fetch() de style Ajax est envoyé à /is_admin, dont le gestionnaire est la fonction suivante, is_admin().
  3. Le jeton d'ID Firebase est transmis dans le corps de la requête POST à is_admin(), qui le récupère dans les en-têtes et appelle le SDK Admin Firebase pour le valider. S'il s'agit d'un utilisateur valide, extrayez son adresse e-mail et vérifiez s'il s'agit d'un administrateur.
  4. Le résultat booléen est ensuite renvoyé au modèle sous la forme d'une erreur 200 réussie.

Ajoutez is_admin() à main.py juste après _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

L'intégralité du code des deux fonctions est nécessaire pour répliquer la fonctionnalité disponible du service Users, en particulier sa fonction is_current_user_admin(). Dans le module 20, cet appel de fonction a fait le gros du travail, contrairement au module 21, dans lequel nous implémentons une solution de remplacement. Heureusement, l'application ne dépend plus d'un service App Engine uniquement. Vous pouvez donc la déplacer vers Cloud Run ou d'autres services. De plus, vous pouvez également modifier la définition d'un "utilisateur administrateur" pour vos propres applications en basculant simplement vers les rôles souhaités dans _TARGETS, tandis que le service Users est codé en dur pour les rôles d'administrateur App Engine.

Initialiser Firebase Auth et mettre en cache les administrateurs App Engine

Nous aurions pu initialiser Firebase Auth en haut à proximité de l'endroit où l'application Flask est initialisée et le client API Cloud NDB créé, mais cela n'a pas été nécessaire tant que tout le code d'administration n'a pas été défini, ce qui est le cas à présent. De même, maintenant que _get_gae_admins() est défini, appelez-le pour mettre en cache la liste des administrateurs.

Ajoutez ces lignes juste en dessous du corps de la fonction de is_admin():

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

Accéder aux mises à jour du modèle de données

Le modèle de données Visit ne change pas. L'accès à Datastore nécessite l'utilisation explicite du gestionnaire de contexte client de l'API Cloud NDB, ds_client.context(). Dans le code, cela signifie que vous encapsulez les appels Datastore dans store_visit() et fetch_visits() dans des blocs Python with. Cette mise à jour est identique au module 2. Apportez les modifications suivantes:

AVANT:

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)

APRÈS:

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)

Déplacer la logique de connexion des utilisateurs vers un modèle Web

Le service Utilisateurs d'App Engine est côté serveur, tandis que Firebase Auth et Cloud Identity Platform sont principalement côté client. Par conséquent, une grande partie du code de gestion des utilisateurs du module 20 est transférée vers le modèle Web du module 21.

Dans main.py, le contexte Web transmet cinq données essentielles au modèle. Les quatre premières listées sont liées à la gestion des utilisateurs et diffèrent selon que l'utilisateur est connecté ou non:

  • who : adresse e-mail de l'utilisateur s'il est connecté ou user dans les autres cas
  • admin : badge (admin) si l'utilisateur connecté est un administrateur
  • sign : afficher le bouton Login (Se connecter) ou Logout (Se déconnecter)
  • link : liens de connexion ou de déconnexion lors d'un clic sur un bouton
  • visits : visites les plus récentes

AVANT:

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

Toute la gestion des utilisateurs est transférée vers le modèle Web. Il ne nous reste donc que les visites, ce qui ramène le gestionnaire principal à ce que nous avions depuis l'application du module 1:

APRÈS:

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

Mettre à jour le modèle Web

À quoi ressemblent toutes les mises à jour de la section précédente dans le modèle ? Nous avons principalement déplacé la gestion des utilisateurs de l'application vers Firebase Auth exécuté dans le modèle, et un port partiel de tout le code que nous avons déplacé vers JavaScript. Comme nous avons vu la baisse significative de main.py, attendez-vous à une croissance similaire en templates/index.html.

AVANT:

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

Remplacez l'intégralité du modèle Web par le contenu ci-dessous:

APRÈS:

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

Ce corps HTML comporte de nombreux composants. Examinons-les les uns après les autres.

Importations Firebase

Toujours dans l'en-tête du document HTML, une fois le titre de la page dépassé, importez les composants Firebase nécessaires. Les composants Firebase sont désormais divisés en plusieurs modules pour plus d'efficacité. Le code permettant d'initialiser Firebase est importé depuis le module principal de l'application Firebase, tandis que les fonctions qui gèrent l'authentification Firebase, Google en tant que fournisseur d'authentification, la connexion et la déconnexion, ainsi que l'état d'authentification changent de "rappel" sont tous importés depuis le module 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";

Configuration de Firebase

Plus tôt dans la partie de ce tutoriel consacrée à la configuration d'Identity Platform, vous avez enregistré les éléments apiKey et authDomain à partir de la boîte de dialogue Application Setup Details (Détails de la configuration de l'application). Ajoutez ces valeurs à la variable firebaseConfig dans la section suivante. Un lien vers des instructions plus détaillées est fourni dans les commentaires:

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

Initialisation de Firebase

La section suivante initialise Firebase avec ces informations de configuration.

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

Cela permet de définir la possibilité d'utiliser Google comme fournisseur d'authentification. Il permet également d'afficher le sélecteur de compte en commentaire, même si un seul compte Google est enregistré dans votre session de navigateur. En d'autres termes, si vous possédez plusieurs comptes, cet outil de sélection de compte comme prévu: a38369389b7c4c7e.png Toutefois, si la session ne compte qu'un seul utilisateur, le processus de connexion se termine automatiquement sans aucune intervention de l'utilisateur. (La fenêtre pop-up s'affiche, puis disparaît.) Vous pouvez forcer l'affichage de la boîte de dialogue du sélecteur de compte pour un utilisateur (au lieu de se connecter immédiatement à l'application) en annulant la mise en commentaire de la ligne du paramètre personnalisé. Si cette option est activée, même les connexions utilisateur uniques font apparaître l'outil de sélection de compte: b75624cb68d94557.png

Fonctions de connexion et de déconnexion

Les lignes de code suivantes constituent les fonctions utilisées pour les clics sur les boutons de connexion ou de déconnexion:

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

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

Actions de connexion et de déconnexion

La dernière section majeure de ce bloc <script> est la fonction appelée pour chaque modification d'authentification (connexion ou déconnexion).

// 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 du module 20 déterminant s'il faut envoyer un message de type "utilisateur connecté" un contexte de modèle plutôt qu'un "utilisateur déconnecté" le contexte est transféré ici. La condition en haut génère true si l'utilisateur s'est connecté correctement, ce qui déclenche les actions suivantes:

  1. L'adresse e-mail de l'utilisateur est configurée de manière à être affichée.
  2. Le bouton Login (Se connecter) devient Logout (Déconnexion).
  3. Un appel de style Ajax à /is_admin est effectué pour déterminer s'il faut afficher le badge administrateur (admin).

Lorsque l'utilisateur se déconnecte, la clause else est exécutée pour réinitialiser toutes les informations utilisateur:

  1. Nom d'utilisateur défini sur user
  2. Badge d'administrateur supprimé
  3. Le bouton Logout (Déconnexion) est à nouveau remplacé par Login (Connexion).

Variables de modèle

Une fois la section d'en-tête terminée, le corps principal commence par les variables du modèle qui sont remplacées par des éléments HTML qui changent si nécessaire:

  1. Nom d'utilisateur affiché
  2. Badge administrateur (admin) (le cas échéant)
  3. Bouton Login (Se connecter) ou Logout (Se déconnecter)
<body>
<p>
Welcome, <span id="who"></span> <span id="admin"><code>(admin)</code></span>
<button id="logbtn"></button>
</p><hr>

Dernières visites et variables d'éléments HTML

Le code des visites les plus récentes ne change pas, et le bloc <script> final définit les variables des éléments HTML qui changent pour la connexion et la déconnexion, comme indiqué ci-dessus:

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

Vous avez maintenant terminé les modifications nécessaires au modèle d'application et au modèle Web pour passer d'App Engine NDB et des API Users à Cloud NDB et Identity Platform, ainsi qu'à la mise à niveau vers Python 3. Félicitations, vous êtes arrivé sur la nouvelle application exemple du module 21 ! Notre version peut être consultée dans le dossier du dépôt du module 21b.

La partie suivante de l'atelier de programmation est facultative (*) et réservée aux utilisateurs dont les applications doivent rester sur Python 2. Elle vous guidera tout au long des étapes nécessaires pour obtenir une application Python 2 Module 21 opérationnelle.

6. *Rétroportage Python 2

Cette section facultative s'adresse aux développeurs qui effectuent une migration d'Identity Platform, mais qui doivent continuer à s'exécuter sur l'environnement d'exécution Python 2. Si ce n'est pas votre cas, ignorez cette section.

Pour créer une version Python 2 fonctionnelle de l'application du module 21, vous avez besoin des éléments suivants:

  1. Conditions d'exécution: fichiers de configuration compatibles avec Python 2 et modifications requises dans l'application principale pour éviter les incompatibilités avec Python 3.
  2. Modification mineure de la bibliothèque:Python 2 était obsolète avant l'ajout de certaines fonctionnalités requises à la bibliothèque cliente Resource Manager. Par conséquent, vous avez besoin d'un autre moyen d'accéder à cette fonctionnalité manquante.

Commençons par la configuration.

Restaurer appengine_config.py

Plus tôt dans ce tutoriel, vous avez été invité à supprimer appengine_config.py, car il n'est pas utilisé par l'environnement d'exécution Python 3 App Engine. Pour Python 2, non seulement il doit être conservé, mais le appengine_config.py du module 20 doit être mis à jour pour permettre l'utilisation des bibliothèques tierces intégrées, à savoir grpcio et setuptools. Ces packages sont requis chaque fois que votre application App Engine utilise des bibliothèques clientes Cloud, telles que celles de Cloud NDB et de Cloud Resource Manager.

Vous allez ajouter ces packages à app.yaml dans un instant, mais pour que votre application puisse y accéder, la fonction pkg_resources.working_set.add_entry() de setuptools doit être appelée. Cela permet aux bibliothèques tierces copiées (auto-groupées ou fournies par des fournisseurs) installées dans le dossier lib de communiquer avec les bibliothèques intégrées.

Implémentez les mises à jour suivantes dans votre fichier appengine_config.py pour appliquer ces modifications:

AVANT:

from google.appengine.ext import vendor

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

Ce code seul ne suffit pas pour permettre l'utilisation de setuptools et grpcio. Quelques lignes supplémentaires sont nécessaires. Modifiez appengine_config.py pour qu'il se présente comme suit:

APRÈS:

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)

Pour en savoir plus sur les modifications requises pour prendre en charge les bibliothèques clientes Cloud, consultez la documentation sur la migration de services groupés.

app.yaml

Comme pour appengine_config.py, vous devez rétablir le fichier app.yaml dans un fichier compatible avec Python 2. Commençons par le app.yaml du module 20 d'origine:

AVANT:

runtime: python27
threadsafe: yes
api_version: 1

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

En plus de setuptools et grpcio, comme indiqué précédemment, il existe une dépendance (qui n'est pas explicitement liée à la migration Identity Platform) qui nécessite l'utilisation de la bibliothèque cliente Cloud Storage et qui nécessite un autre package tiers intégré, ssl. Ajoutez les trois dans une nouvelle section libraries, en sélectionnant la dernière version. versions disponibles de ces packages pour app.yaml:

APRÈS:

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

Pour le module 21, nous avons ajouté Google Auth, Cloud NDB, Cloud Resource Manager et Firebase Admin SDK à la version requirements.txt pour Python 3. La situation pour Python 2 est plus complexe:

  • L'API Resource Manager fournit la fonctionnalité d'autorisation requise pour l'application exemple. Malheureusement, cette compatibilité n'était pas encore disponible dans la version finale Python 2 de la bibliothèque cliente Cloud Resource Manager. Il n'est disponible que dans la version Python 3.
  • Par conséquent, une autre manière d'accéder à cette fonctionnalité à partir de l'API est nécessaire. La solution consiste à utiliser la bibliothèque cliente des API Google de niveau inférieur pour communiquer avec l'API. Pour passer à cette bibliothèque cliente, remplacez google-cloud-resource-manager par le package google-api-python-client de niveau inférieur.
  • Python 2 a été arrêté, le graphique de dépendances prenant en charge le module 21 nécessite donc le verrouillage de certains packages sur des versions spécifiques. Certains packages doivent être appelés même s'ils ne sont pas spécifiés dans le fichier app.yaml de Python 3.

AVANT:

flask

À partir du requirements.txt du module 20, mettez-le à jour comme suit pour une application du module 21 qui fonctionne:

APRÈS:

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

Les numéros de package et de version seront mis à jour dans le dépôt à mesure que les dépendances changent, mais cet élément app.yaml est suffisant pour une application fonctionnelle au moment de la rédaction de ce document.

Autres mises à jour de configuration

Si vous n'avez pas supprimé le dossier lib précédemment dans cet atelier de programmation, faites-le maintenant. Avec la nouvelle version de requirements.txt, exécutez la commande familière suivante pour installer ces exigences dans lib:

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

Si Python 2 et 3 sont installés sur votre système de développement, vous devrez peut-être utiliser pip2 au lieu de pip.

Modifier le code d'application

Heureusement, la plupart des modifications requises se trouvent dans les fichiers de configuration. La seule modification nécessaire au code de l'application est une mise à jour mineure permettant d'utiliser la bibliothèque cliente des API Google de niveau inférieur au lieu de la bibliothèque cliente Resource Manager pour accéder à l'API. Aucune mise à jour du modèle Web templates/index.html n'est requise.

Importations et initialisation des mises à jour

Remplacez la bibliothèque cliente Resource Manager (google.cloud.resourcemanager) par la bibliothèque cliente des API Google (googleapiclient.discovery), comme illustré ci-dessous:

AVANT:

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

APRÈS:

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

Assistance pour les administrateurs App Engine

Quelques modifications sont nécessaires dans _get_gae_admins() pour permettre l'utilisation de la bibliothèque cliente de niveau inférieur. Parlons d'abord de ce qui change, puis vous vous donnerons tout le code à mettre à jour.

Le code Python 2 nécessite l'utilisation des identifiants et de l'ID de projet renvoyés par google.auth.default(). Les identifiants ne sont pas utilisés dans Python 3. Ils ont donc été attribués à une variable factice générique ( _ ). Étant donné qu'il est nécessaire pour la version Python 2, remplacez le trait de soulignement par CREDS. De plus, au lieu de créer un client API Resource Manager, vous allez créer un point de terminaison de service d'API, dont le concept est semblable à celui d'un client API. Nous allons donc conserver le même nom de variable (rm_client). L'une des différences est que l'instanciation d'un point de terminaison de service nécessite des identifiants (CREDS).

Ces modifications sont reflétées dans le code ci-dessous:

AVANT:

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

APRÈS:

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'autre différence est que la bibliothèque cliente Resource Manager renvoie des objets allow-policy qui utilisent une notation d'attribut en pointillés, tandis que la bibliothèque cliente de niveau inférieur renvoie des dictionnaires Python utilisant des crochets ( [ ]). Par exemple, utilisez binding.role pour la bibliothèque cliente Resource Manager et binding['role'] pour la bibliothèque de niveau inférieur. Le premier utilise également les caractères "séparés par des traits de soulignement" par rapport à la bibliothèque de niveau inférieur préférant "CamelCased" ainsi qu'une manière légèrement différente de transmettre les paramètres de l'API.

Ces différences d'utilisation sont indiquées ci-dessous:

AVANT:

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)

APRÈS:

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

En réunissant toutes ces modifications, remplacez le fichier _get_gae_admins() Python 3 par cette version Python 2 équivalente:

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 fonction is_admin() ne nécessite aucune mise à jour, car elle repose sur _get_gae_admins(), qui a déjà été mis à jour.

Vous êtes arrivé à la fin des modifications requises pour rétroporter l'application du module 21 Python 3 vers Python 2. Félicitations, vous êtes arrivé sur votre application exemple mise à jour dans le module 21 ! Vous trouverez l'intégralité du code dans le dossier du dépôt du module 21a.

7. Résumé/Nettoyage

Les dernières étapes de l'atelier de programmation consistent à vérifier que les comptes principaux (utilisateurs ou comptes de service) exécutant cette application disposent des autorisations appropriées, puis à déployer votre application pour vérifier qu'elle fonctionne comme prévu et que les modifications sont répercutées dans le résultat.

Permet de lire l'autorisation IAM allow-policy

Précédemment, nous vous avons présenté les quatre rôles requis pour être reconnu en tant qu'administrateur App Engine. Nous vous en proposons maintenant un cinquième:

  • roles/viewer
  • roles/editor
  • roles/owner
  • roles/appengine.appAdmin
  • roles/resourcemanager.projectIamAdmin (pour les comptes principaux accédant à la règle d'autorisation IAM)

Le rôle roles/resourcemanager.projectIamAdmin permet aux comptes principaux de déterminer si un utilisateur final est membre de l'un des rôles d'administrateur App Engine. Sans appartenance à roles/resourcemanager.projectIamAdmin, les appels à l'API Cloud Resource Manager pour obtenir la règle d'autorisation échoueront.

Vous n'avez pas besoin d'effectuer une action explicite dans ce cas, car votre application s'exécutera avec le compte de service par défaut d'App Engine, qui bénéficie automatiquement de ce rôle. Même si vous utilisez le compte de service par défaut pendant la phase de développement, nous vous recommandons vivement de créer et d'utiliser un compte de service géré par l'utilisateur avec les autorisations minimales requises pour que votre application fonctionne correctement. Pour accorder l'adhésion à un tel compte de service, exécutez la commande suivante:

$ 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 est l'ID du projet Cloud et USR_MGD_SVC_ACCT@PROJ_ID.iam.gserviceaccount.com est le compte de service géré par l'utilisateur que vous créez pour votre application. Cette commande génère la stratégie IAM mise à jour de votre projet, dans laquelle vous pouvez vérifier que le compte de service est membre de roles/resourcemanager.projectIamAdmin. Pour en savoir plus, consultez la documentation de référence. Pour rappel, vous n'avez pas besoin d'exécuter cette commande dans cet atelier de programmation, mais enregistrez-la comme référence pour moderniser vos propres applications.

Déployer et vérifier l'application

Importez votre application dans le cloud à l'aide de la commande gcloud app deploy standard. Une fois déployé, vous devriez constater une fonctionnalité presque identique à celle de l'application du module 20, à la différence que vous avez remplacé le service Utilisateurs d'App Engine par Cloud Identity Platform (et Firebase Auth) pour la gestion des utilisateurs:

3a83ae745121d70.png

Une différence que vous remarquerez par rapport au module 20 est que lorsque vous cliquez sur "Connexion", un pop-up s'affiche au lieu d'une redirection, comme illustré dans certaines des captures d'écran ci-dessous. Toutefois, comme pour le module 20, le comportement diffère légèrement selon le nombre de comptes Google enregistrés dans le navigateur.

Si aucun utilisateur n'est enregistré dans le navigateur ou si un utilisateur unique ne s'est pas encore connecté, un pop-up de connexion Google générique s'affiche:

8437f5f3d489a942.png

Si un utilisateur unique est enregistré dans votre navigateur, mais qu'il se connecte ailleurs, aucune boîte de dialogue ne s'affiche (ou elle s'affiche et se ferme immédiatement), et l'application passe à l'état connecté (l'adresse e-mail de l'utilisateur et le bouton Déconnexion s'affichent).

Certains développeurs peuvent souhaiter fournir un sélecteur de compte, même pour un seul utilisateur:

b75624cb68d94557.png

Pour ce faire, annulez la mise en commentaire de la ligne provider.setCustomParameters({prompt: 'select_account'}); dans le modèle Web, comme décrit précédemment.

S'il y a plusieurs utilisateurs, la boîte de dialogue de l'outil de sélection de compte s'affiche (voir ci-dessous). S'il n'est pas encore connecté, une invite s'affiche. Si vous êtes déjà connecté, la fenêtre pop-up disparaît et l'application passe à l'état de connexion.

c454455b6020d5e4.png

L'état de connexion du module 21 est identique à celui de l'interface utilisateur du module 20:

49ebe4dcc1eff11f.png

Il en va de même pour les administrateurs connectés:

44302f35b39856eb.png

Contrairement au module 21, le module 20 accède toujours à la logique du contenu du modèle Web à partir de l'application (code côté serveur). L'un des défauts du module 20 est qu'une visite est enregistrée lorsque l'utilisateur final accède à l'application pour la première fois, et une autre lorsqu'il se connecte.

Dans le module 21, la logique de connexion ne s'applique qu'au modèle Web (code côté client). Il n'est pas nécessaire de se déplacer côté serveur pour déterminer le contenu à afficher. Le seul appel effectué vers le serveur est la vérification des administrateurs après la connexion d'un utilisateur final. Cela signifie que les connexions et les déconnexions n'enregistrent pas de visites supplémentaires. Par conséquent, la liste des visites les plus récentes reste constante pour les actions de gestion des utilisateurs. Notez que les captures d'écran ci-dessus montrent le même ensemble de quatre visites avec plusieurs connexions utilisateur.

Les captures d'écran du module 20 illustrent le problème au début de cet atelier de programmation. Des journaux de visites distincts sont affichés pour chaque action de connexion ou de déconnexion. Vérifiez les codes temporels de la visite la plus récente pour chaque capture d'écran dans l'ordre chronologique.

Effectuer un nettoyage

Général

Si vous avez terminé, nous vous recommandons de désactiver votre application App Engine afin d'éviter que des frais ne vous soient facturés. Toutefois, si vous souhaitez effectuer d'autres tests, la plate-forme App Engine dispose d'un quota sans frais. Tant que vous ne dépassez pas ce niveau d'utilisation, aucuns frais ne vous seront facturés. Cela concerne le calcul, mais des frais peuvent également s'appliquer pour les services App Engine concernés. Pour en savoir plus, consultez sa page des tarifs. Si cette migration implique d'autres services cloud, ceux-ci sont facturés séparément. Dans les deux cas, le cas échéant, consultez la section "Informations spécifiques à cet atelier de programmation" ci-dessous.

Afin d'informer l'ensemble des utilisateurs, le déploiement sur une plate-forme de calcul sans serveur Google Cloud comme App Engine entraîne des coûts minimes de compilation et de stockage. Cloud Build et Cloud Storage disposent de leur propre quota sans frais. Le stockage de cette image utilise une partie de ce quota. Cependant, vous pouvez résider dans une région qui n'offre pas ce type de version sans frais. Vous devez donc surveiller l'utilisation de votre espace de stockage afin de réduire les coûts potentiels. "Dossiers" Cloud Storage spécifiques vous devez examiner:

  • 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
  • Les liens de stockage ci-dessus dépendent de votre PROJECT_ID et de votre LOC (par exemple, "us") si votre application est hébergée aux États-Unis.

En revanche, si vous ne comptez pas utiliser cette application ou d'autres ateliers de programmation liés à la migration, et que vous souhaitez tout supprimer complètement, arrêtez votre projet.

Spécifique à cet atelier de programmation

Les services listés ci-dessous sont propres à cet atelier de programmation. Pour en savoir plus, consultez la documentation de chaque produit:

  • Le service App Engine Datastore est fourni par Cloud Datastore (Cloud Firestore en mode Datastore), également disponible avec une version sans frais. consultez la page des tarifs pour en savoir plus.
  • Cloud Identity Platform offre un certain niveau de sans frais, selon les services que vous utilisez. Consultez sa page des tarifs pour en savoir plus.
  • L'utilisation de l'API Cloud Resource Manager est sans frais dans la plupart des cas, conformément à sa page de tarification.

Étapes suivantes

Au-delà de ce tutoriel, d'autres modules de migration à envisager concernant l'abandon des anciens services groupés sont les suivants:

  • Module 2: Migrer de l'environnement ndb App Engine vers Cloud NDB
  • Modules 7 à 9: migration de la file d'attente des tâches App Engine (tâches d'envoi) vers Cloud Tasks
  • Modules 12 à 13: Migrer de Memcache d'App Engine vers Cloud Memorystore
  • Modules 15 à 16: effectuer la migration d'un paquet d'application App Engine vers Cloud Storage
  • Modules 18 à 19: Migrer de la file d'attente de tâches App Engine (tâches d'extraction) vers Cloud Pub/Sub

App Engine n'est plus la seule plate-forme sans serveur de Google Cloud. Si vous disposez d'une petite application App Engine ou d'une application aux fonctionnalités limitées et que vous souhaitez la transformer en microservice autonome, ou si vous voulez diviser une application monolithique en plusieurs composants réutilisables, nous vous recommandons de passer à Cloud Functions. Si la conteneurisation fait désormais partie de votre workflow de développement d'applications, en particulier si elle consiste en un pipeline CI/CD (intégration continue/livraison continue ou déploiement), envisagez de migrer vers Cloud Run. Ces scénarios sont abordés dans les modules suivants:

  • Effectuer une migration d'App Engine vers Cloud Functions: consultez le Module 11
  • Migrer d'App Engine vers Cloud Run: consultez le module 4 pour conteneuriser votre application avec Docker, ou le module 5 pour effectuer cette opération sans conteneur, ni connaissance de Docker ou Dockerfile.

Le passage à une autre plate-forme sans serveur est facultatif. Nous vous recommandons de réfléchir aux meilleures options pour vos applications et cas d'utilisation avant d'apporter des modifications.

Quel que soit le module de migration que vous envisagez ensuite, tout le contenu de la station de migration sans serveur (ateliers de programmation, vidéos, code source [si disponible]) est accessible dans son dépôt Open Source. Le fichier README du dépôt fournit également des indications sur les migrations à prendre en compte et sur l'ordre d'exécution approprié. des modules de migration.

8. Ressources supplémentaires

Vous trouverez ci-dessous des ressources supplémentaires destinées aux développeurs qui explorent ce module ou ceux qui y sont associés. Vous trouverez ci-dessous vos commentaires sur ce contenu, ainsi que des liens vers le code et divers éléments de documentation qui pourraient vous être utiles.

Commentaires et problèmes concernant les ateliers de programmation

Si vous rencontrez des problèmes avec cet atelier de programmation, commencez par faire une recherche avant de les signaler. Liens vers la recherche et la création d'un signalement :

Ressources de migration

Le tableau ci-dessous contient des liens vers les dossiers de dépôt des modules 20 (START) et 21 (FINISH).

Atelier de programmation

Python 2

Python 3

Module 20

code

(n/a)

Module 21 (cet atelier de programmation)

code

code

Références en ligne

Vous trouverez ci-dessous des ressources pertinentes pour ce tutoriel:

Cloud Identity Platform et Cloud Marketplace

Cloud Resource Manager, Cloud IAM, SDK Firebase Admin

Utilisateurs App Engine, App Engine NDB, Cloud NDB, Cloud Datastore

Autres références du module de migration

Migration App Engine

Plate-forme App Engine

SDK Cloud

Autres informations sur le cloud

Vidéos

Licence

Ce document est publié sous une licence Creative Commons Attribution 2.0 Generic.