Créer une application de flacon avec Google Login – Real Python

By | juillet 17, 2019

python pour débutant

Vous avez probablement déjà vu l’option pour Connexion Google sur divers sites. Certains sites ont aussi plus d'options comme Identifiant Facebook ou Connexion GitHub. Toutes ces options permettent aux utilisateurs d’utiliser les comptes existants pour utiliser un nouveau service.

Dans cet article, vous allez créer une application Web Flask. Votre application permettra à un utilisateur de se connecter en utilisant son identité Google au lieu de créer un nouveau compte. Cette méthode de gestion des utilisateurs présente de nombreux avantages. Ce sera plus simple et plus sûr que de gérer les combinaisons traditionnelles de nom d’utilisateur et de mot de passe.

Cet article sera plus simple si vous comprenez déjà les bases de Python. Il serait également utile de connaître un peu les frameworks Web et les requêtes HTTP, mais ce n’est pas strictement nécessaire.

À la fin de cet article, vous pourrez:

  • Créer une application Web Flask permettant aux utilisateurs de se connecter avec Google
  • Créer des informations d'identification client pour interagir avec Google
  • Utiliser Flask-Login pour la gestion de session utilisateur dans une application Flask
  • Mieux comprendre OAuth 2 et OpenID Connect (OIDC)

Vous pouvez cliquer sur la case ci-dessous pour obtenir le code de l'application que vous allez créer dans cet article:

Pourquoi utiliser Google Login pour vos utilisateurs?

Vous voudrez peut-être que les utilisateurs individuels aient des profils. Ou peut-être souhaitez-vous proposer des fonctionnalités à certains utilisateurs uniquement. Dans tous les cas, vous devez savoir qui interagit avec votre application. En d’autres termes, vous devrez authentifier les utilisateurs et les identifier de manière unique.

La solution traditionnelle consiste à utiliser un nom d'utilisateur unique et un mot de passe secret. Votre application stockera ces informations et les demandera en cas de besoin. Cependant, cette solution présente quelques inconvénients:

  • Vous devez gérer les mots de passe en toute sécurité.
  • Vous devez implémenter toute fonctionnalité liée au compte:
    • Authentification à deux facteurs
    • Réinitialiser le mot de passe
  • Vous devez vous protéger contre les tentatives de connexion malveillantes.
  • Vos utilisateurs doivent se rappeler encore un autre nom d'utilisateur et mot de passe.

En utilisant la connexion Google pour vos utilisateurs, vous leur confiez toute cette responsabilité. Votre application attend que l'utilisateur passe par l'authentification. Google informe ensuite votre application de cet utilisateur. À ce stade, vous pouvez les connecter efficacement à votre application.

Vous n’avez pas besoin de stocker de mots de passe et Google se charge de la sécurité.

Comment les applications utilisent Google Login

Il existe deux spécifications très populaires et importantes appelées OAuth 2 et OpenID Connect (OIDC). OIDC est construit sur OAuth 2, ajoutant quelques idées et concepts nouveaux.

Ces spécifications définissent comment une application tierce peut obtenir des informations d'un autre service. Cela implique généralement l'obtention du consentement d'un utilisateur. Pour décompresser un peu cela, voyons comment cela s’applique à l’application que vous êtes sur le point de construire.

Vous êtes sur le point d’écrire une application tierce qui permettra à un utilisateur d’utiliser une Connexion Google pour vous connecter. Pour ce faire, Google a besoin de connaître votre application. Heureusement, vous pouvez enregistrer votre application en tant que client auprès de Google.

Une fois qu'un utilisateur vient à votre application et appuie sur le bouton Connexion Google bouton, vous pouvez les envoyer à Google. À partir de là, Google doit s’assurer que l’utilisateur consent à transmettre son courrier électronique et d’autres informations à votre application. Si l'utilisateur y consent, Google renvoie certaines informations à votre application. Vous stockez ensuite ces informations et pouvez les référencer ultérieurement, en connectant effectivement l'utilisateur.

OpenID Connect Détails

Pour demander des informations au nom d’un utilisateur, vous devez devenir un client au serveur d'authentification, également appelé fournisseur. La première chose que vous constaterez si vous approfondissez ces spécifications est qu’il existe de nombreux termes et concepts qui se chevauchent.

Par conséquent, en tant qu’application tierce (également appelée client), vous souhaitez obtenir des informations du fournisseur pour le compte de l’utilisateur. Une série d’étapes permet de réaliser cela, et ces étapes doivent se dérouler dans un ordre spécifique. C’est pourquoi vous entendrez parfois OAuth 2 et OpenID Connect appelé une poignée de main, couler, ou Danse.

Ces étapes sont, en gros:

  1. Vous enregistrez une application tierce en tant que client auprès du fournisseur:
    • Vous recevez des informations d'identification client uniques du fournisseur.
    • Vous utiliserez ces informations d'identification client pour vous authentifier (prouver qui vous êtes) auprès du fournisseur ultérieurement.
  2. Le client envoie une demande au fournisseur du fournisseur. autorisation URL
  3. Le fournisseur demande à l'utilisateur de s'authentifier (prouver son identité)
  4. Le fournisseur demande à l'utilisateur de consentir à ce que le client agisse en son nom:
    • Cela inclut généralement un accès limité et indique clairement à l'utilisateur ce que le client demande.
    • C'est comme si vous deviez approuver une application sur votre téléphone pour accéder à l'emplacement ou aux contacts.
  5. Le fournisseur envoie au client un code d'autorisation unique.
  6. Le client renvoie le code d'autorisation à l'adresse du fournisseur. jeton URL
  7. Le fournisseur envoie les jetons client à utiliser avec d'autres URL de fournisseur pour le compte de l'utilisateur.

Ces étapes incluent les deux normes mentionnées jusqu'à présent. OpenID Connect (OIDC) est basé sur OAuth 2, ajoutant quelques fonctionnalités et exigences supplémentaires, impliquant principalement le processus d'authentification. Outre l’authentification mentionnée dans le flux ci-dessus, les concepts OIDC importants pour votre application sont les suivants: configuration du fournisseur et point de terminaison userinfo.

le configuration du fournisseur contient des informations sur le fournisseur, y compris les URL exactes à utiliser pour le flux OAuth 2. Il existe une URL standard sur un fournisseur OIDC que vous pouvez utiliser pour récupérer un document contenant des champs normalisés.

le point de terminaison userinfo renverra des informations sur l'utilisateur après avoir suivi le flux OAuth 2. Cela inclura leur email et certaines informations de base du profil que vous utiliserez dans votre application. Pour obtenir ces informations sur l'utilisateur, vous aurez besoin d'un jeton auprès du fournisseur, comme décrit à la dernière étape de la procédure ci-dessus.

Vous verrez les détails sur la manière dont la configuration du fournisseur et le point de terminaison des informations utilisateur peuvent être utilisés ultérieurement.

Créer un client Google

La première étape pour activer un Connexion Google L’option consiste à enregistrer votre application en tant que client auprès de Google. Passons en revue les étapes pour le faire.

Tout d'abord, notez que vous aurez besoin d'un compte Google. Vous en avez déjà un si vous utilisez Gmail.

Ensuite, accédez à la page Informations d'identification des développeurs Google.

Une fois dedans, vous serez peut-être invité à accepter leurs conditions d'utilisation. Si vous acceptez ces conditions, appuyez sur le bouton Créer des identifiants bouton sur la page suivante. Sélectionnez l'option pour ID client OAuth:

Google créer des informations d'identification capture d'écran

Sélectionnez le application Web option en haut. Vous pouvez donner un nom au client dans la prénom domaine aussi. Le nom que vous fournissez sera affiché aux utilisateurs lorsqu'ils consentiront à ce que votre application agisse en leur nom.

Vous exécuterez votre application Web localement pour le moment, vous pouvez donc définir la Origines JavaScript autorisées à https://127.0.0.1:5000 et URI de redirection autorisés à https://127.0.0.1:5000/login/callback. Cela permettra à votre application Flask locale de communiquer avec Google.

Enfin, appuyez sur Créer et prendre note de la identité du client et secret client. Vous aurez besoin des deux plus tard.

Création de votre propre application Web

Passons maintenant à la partie amusante dans laquelle vous appliquez les connaissances acquises pour créer une application Web réelle!

Commençons par le but en tête. Vous souhaitez créer une application permettant aux utilisateurs de se connecter avec leur compte Google. Cette application devrait pouvoir récupérer certaines informations de base sur l'utilisateur à partir de Google, telles que son adresse e-mail. Ensuite, l'application doit stocker les informations utilisateur de base dans une base de données.

Voyons d’abord le framework et les bibliothèques que vous utiliserez.

Ballon

Flask est un framework web léger, auto-proclamé microframework. Il est livré avec des outils intégrés pour les tâches de base qu'une application Web va effectuer, telles que le routage des URL et la gestion des requêtes HTTP.

J'ai choisi d'utiliser Flask comme exemple pour sa popularité et sa simplicité. Cependant, les connaissances acquises sur OAuth 2 et OIDC ne sont pas spécifiques à Flask. En fait, même la bibliothèque que vous utiliserez pour faciliter OAuth 2 et OIDC est utilisable dans n’importe quel code Python. En d’autres termes, avec quelques modifications mineures, vous pouvez utiliser ce que vous avez appris ici et l’appliquer à un autre cadre de votre choix.

Flask-Login

Flask_login est un autre outil que vous pouvez utiliser pour faciliter la gestion des utilisateurs. gestion de session utilisateur.

Cette bibliothèque fait quelques choses en coulisse et vous donne quelques outils pour aider les utilisateurs. À savoir, il fournit des utilitaires pour vous permettre de savoir quand un utilisateur est connecté et déconnecté. Pour ce faire, il gère une session utilisateur dans un cookie du navigateur.

Il gère également la connexion et la déconnexion des utilisateurs, y compris la création d'entrées de base de données pour ces utilisateurs. Cependant, du point de vue de votre code, cela simplifie vraiment tout le processus (ce que vous verrez bientôt).

OAuthLib

Il existe une phrase commune qui s’applique très bien pour le code lié à la sécurité et conforme à la norme: «Ne réinventez pas la roue».

Les normes OAuth 2 et OpenID Connect sont compliquées. Consultez le RFC et les spécifications et vous verrez. Ils sont denses. Une erreur signifie que vous pourriez ouvrir une vulnérabilité dans votre application.

Donc, vous n'écrirez pas de code pour implémenter ces normes. Vous allez utiliser un package Python qui a été choisi sur des critères très spécifiques:

  1. C’est une bibliothèque populaire et généralement recommandée. Beaucoup d'autres paquets utilisent cette bibliothèque en interne.
  2. C'est très actif, avec des gens qui corrigent des bugs fréquemment.
  3. C’est dur au combat et existe depuis 2012.

Il existe des packages spécifiques à l'infrastructure Web qui utilisent cette bibliothèque pour une intégration plus étroite dans Flask, Django, Pyramid, etc. Cependant, pour conserver le code que vous apprendrez ici, vous utiliserez cette bibliothèque directement sans aucun wrapper sophistiqué.

Installation de dépendances

Vous utiliserez un certain nombre de dépendances tierces pour vous simplifier la vie. Voici un résumé de ces dépendances:

  • Un framework web pour faciliter les tâches typiques des applications web (Flask)
  • Un moyen de gérer les sessions utilisateur sans maux de tête (Flask-Login)
  • Une bibliothèque OIDC durcie au combat (oauthlib)

De plus, vous utiliserez les éléments suivants:

  • Une base de données pour stocker des informations sur les utilisateurs qui se connectent (SQLite)
  • Un moyen convivial d’envoyer des requêtes HTTP à Google (demandes)
  • Un moyen rapide d'activer en toute sécurité avec https localement (pyOpenSSL)

SQLite fait partie de la bibliothèque standard Python, mais pas les autres packages. Donc, vous avez deux dépendances à installer. Pour l'instant, passons à la création de cette application, étape par étape.

Tout d'abord, vous devrez installer les dépendances tierces mentionnées ci-dessus. Vous ferez cela en créant un conditions.txt fichier avec le contenu suivant:

requêtes == 2.21.0
Flacon == 1.0.2
oauthlib == 3.0.1
pyOpenSSL == 19.0.0
Flask-Login == 0.4.1

Ensuite, vous pouvez installer ces dépendances en utilisant pépin, Le programme d’installation de paquets Python.

À installer à partir du conditions.txt fichier, exécutez la commande suivante dans votre terminal:

$ pip install -r Requirements.txt

Vous êtes maintenant prêt à faire des vagues! Fouillons dans le code.

Importations, configuration et configuration

Commencez par ajouter quelques fichiers pour prendre en charge certaines fonctionnalités de base de base de données et la gestion des utilisateurs. Celles-ci ne seront pas décrites section par section, principalement parce que plonger dans les détails de l’implémentation de la base de données Python est un trou de lapin qui nous détournerait de notre objectif.

Ce fichier traitera certaines fonctionnalités de la base de données. C’est presque ligne par ligne dans le tutoriel officiel de la base de données de Flask:

# http://flask.pocoo.org/docs/1.0/tutorial/database/
importation sqlite3

importation Cliquez sur
de ballon importation current_app, g
de flask.cli importation with_appcontext

def get_db():
    si "db" ne pas dans g:
        g.db = sqlite3.relier(
            "sqlite_db" http://realpython.com/, detect_types=sqlite3.PARSE_DECLTYPES
        )
        g.db.row_factory = sqlite3.Rangée

    revenir g.db

def close_db(e=Aucun):
    db = g.pop("db" http://realpython.com/, Aucun)

    si db est ne pas Aucun:
        db.Fermer()

def init_db():
    db = get_db()

    avec current_app.open_resource("schema.sql" http://realpython.com/) comme F:
        db.executescript(F.lis().décoder("utf8" http://realpython.com/))

@Cliquez sur.commander("init-db" http://realpython.com/)
@with_appcontext
def init_db_command():
    "" "Effacer les données existantes et créer de nouvelles tables." ""
    init_db()
    Cliquez sur.écho("Initialisé la base de données." Http://realpython.com/)

def init_app(app):
    app.teardown_appcontext(close_db)
    app.cli.add_command(init_db_command)

Maintenant que vous avez des utilitaires de base de données, vous pouvez commencer à penser au schéma. Vous remarquerez peut-être que ce code recherche un schema.sql fichier que vous créerez ensuite.

le schema.sql fichier est juste un SQL qui va créer une table utilisateur dans notre base de données. Vous pouvez voir les champs que vous allez stocker par utilisateur dans ce fichier.

Ici vous avez une seule table, utilisateur, qui hébergera quelques éléments liés aux utilisateurs (leur nom, le courrier électronique avec lequel ils se connectent et leur photo de profil sur Google):

CRÉER TABLE utilisateur (
  identifiant TEXTE PRIMAIRE CLÉ,
  prénom TEXTE NE PAS NUL,
  email TEXTE UNIQUE NE PAS NUL,
  photo de profil TEXTE NE PAS NUL
)

Le code dans le db.py Le fichier exécutera réellement ce SQL pour créer la table dans votre base de données.

Ce fichier suivant contient notre Utilisateur classe, qui stockera et récupérera les informations de la base de données. Le nom, l'e-mail et la photo de profil seront tous récupérés dans Google, comme vous le verrez plus loin dans l'article.

le Utilisateur class a des méthodes pour extraire un utilisateur existant de la base de données et créer un nouvel utilisateur:

de flask_login importation UserMixin

de db importation get_db

classe Utilisateur(UserMixin):
    def __init__(soi, id_, prénom, email, photo de profil):
        soi.identifiant = id_
        soi.prénom = prénom
        soi.email = email
        soi.photo de profil = photo de profil

    @staticmethod
    def obtenir(identifiant d'utilisateur):
        db = get_db()
        utilisateur = db.exécuter(
            "SELECT * FROM utilisateur WHERE id =?" Http://realpython.com/, (identifiant d'utilisateur,)
        ).fetchone()
        si ne pas utilisateur:
            revenir Aucun

        utilisateur = Utilisateur(
            id_=utilisateur[[[[0], prénom=utilisateur[[[[1], email=utilisateur[[[[2], photo de profil=utilisateur[[[[3]
        )
        revenir utilisateur

    @staticmethod
    def créer(id_, prénom, email, photo de profil):
        db = get_db()
        db.exécuter(
            "INSERT INTO user (id, name, email, profile_pic)"
            "VALEURS (?,?,?,?)" Http://realpython.com/,
            (id_, prénom, email, photo de profil),
        )
        db.commettre()

Le code exécute des instructions SQL sur la base de données, qui est extraite du fichier. get_db () fonction de la précédente db.py fichier. Chaque nouvel utilisateur entraîne l'insertion d'une ligne supplémentaire dans la base de données.

Après avoir créé le db.py, schema.sql, et user.py fichiers du code ci-dessus, vous pouvez créer un nouveau app.py fichier. Ajoutez à cela les importations suivantes:

# Bibliothèques standard Python
importation JSON
importation os
importation sqlite3

# Bibliothèques tierces
de ballon importation Ballon, réorienter, demande, url_for
de flask_login importation (
    LoginManager,
    utilisateur actuel,
    Connexion requise,
    login_user,
    logout_user,
)
de oauthlib.oauth2 importation WebApplicationClient
importation demandes

# Importations internes
de db importation init_db_command
de utilisateur importation Utilisateur

Vous les utiliserez plus tard, il n’est donc pas très important de comprendre chacune d’elles pour le moment. La prochaine partie de votre app.py est une configuration:

# Configuration
GOOGLE_CLIENT_ID = os.environ.obtenir("GOOGLE_CLIENT_ID" http://realpython.com/, Aucun)
GOOGLE_CLIENT_SECRET = os.environ.obtenir("GOOGLE_CLIENT_SECRET" http://realpython.com/, Aucun)
GOOGLE_DISCOVERY_URL = (
    "https://accounts.google.com/.well-known/openid-configuration"
)

Voici comment vous stockerez l’ID client Google et le secret client, que vous auriez dû créer plus tôt dans l’article. Celles-ci seront utilisées plus tard dans le flux OIDC.

Votre application essaiera d'obtenir les informations d'identification du client en lisant les variables d'environnement. Il y a quelques raisons à cela:

  1. Il n'est pas nécessaire de modifier votre code ultérieurement si vous souhaitez utiliser des informations d'identification différentes, il vous suffit de mettre à jour l'environnement.
  2. Vous ne pouvez pas commettre accidentellement vos informations d'identification secrètes dans GitHub (ou un autre référentiel public).

De nombreuses personnes ont accidentellement divulgué des secrets à des référentiels publics, posant un risque assez grave pour la sécurité. Il vaut mieux se protéger contre cela en utilisant des variables environnementales.

Sinon, vous pourrait collez les chaînes directement ici et stockez-les dans ces variables.
toutefois, le secret du client devrait ne pas être partagé ou engagé dans un référentiel public. En d'autres termes, veillez à ne pas archiver ce fichier si vous collez ici vos informations d'identification de client réel.

Enfin, vous trouverez ci-dessous du code avec des variables globales et une logique d’initialisation naïve de la base de données. La plupart de ces opérations, autres que l'initialisation de la base de données, constituent le moyen standard de configuration de Flask, Flask-Login et OAuthLib, sur lequel vous avez déjà eu connaissance:

Configuration de l'application Flask
app = Ballon(__prénom__)
app.clef secrète = os.environ.obtenir("SECRET_KEY" http://realpython.com/) ou os.urande(24)

# Configuration de la gestion de session utilisateur
# https://flask-login.readthedocs.io/en/latest
login_manager = LoginManager()
login_manager.init_app(app)

# Configuration de base de données naïve
essayer:
    init_db_command()
sauf sqlite3.OperationalError:
    # Suppose que cela a déjà été créé
    passer

# Configuration du client OAuth 2
client = WebApplicationClient(GOOGLE_CLIENT_ID)

# Assistant flask-Login pour récupérer un utilisateur de notre base de données
@login_manager.user_loader
def utilisateur_charge(identifiant d'utilisateur):
    revenir Utilisateur.obtenir(identifiant d'utilisateur)

Notez que vous utilisez déjà l’ID client de Google pour initialiser notre oauthlib client dans le WebApplicationClient.

Vous pouvez créer une autre variable d'environnement CLEF SECRÈTE que Flask et Flask-Login utiliseront pour signer de manière cryptographique les cookies et autres éléments.

Points de terminaison d'applications Web

Maintenant, pour les trucs amusants. Vous allez écrire quatre points de terminaison pour votre application Web:

  1. Un pour la page d'accueil
  2. Un pour commencer le processus de connexion de l'utilisateur
  3. Un pour un rappel vers lequel Google sera redirigé après qu'un utilisateur se connecte
  4. Un pour se déconnecter

Ces points de terminaison seront définis par différentes URL sur votre application avec des noms très créatifs:

  1. Page d'accueil: /
  2. S'identifier: /s'identifier
  3. Rappel de connexion: / login / rappel
  4. Connectez – Out: /Connectez - Out

Bien sûr, vous voudrez peut-être ajouter des pages et des fonctionnalités supplémentaires ultérieurement. Le résultat final de cette application sera totalement extensible pour ajouter tout ce que vous voulez.

Vous ajouterez tout le code suivant pour ces noeuds finaux dans la app.py fichier. Examinons chacun des codes de ces points de terminaison, un à la fois.

Page d'accueil

Cela n’a rien de fantaisiste sur le plan visuel, mais vous ajouterez une bonne logique pour afficher quelque chose de différent si un utilisateur est connecté. Lorsqu'il ne le sont pas, un lien apparaîtra indiquant que Connexion Google.

Appuyez sur le lien pour les rediriger vers votre /s'identifier point de terminaison, qui initiera le flux de connexion. Une fois la connexion établie, la page d’accueil affiche à la fois le courrier électronique Google de l’utilisateur et la photo de son profil Google public!

Sans plus tarder, vous pouvez commencer à ajouter plus de code à votre app.py fichier:

@app.route("/"http://realpython.com/)
def indice():
    si utilisateur actuel.est_authentifié:
        revenir (
            "

Bonjour, ! Vous êtes connecté! Email:

"
"

Image de profil Google:

" '<img src = "http://realpython.com/"alt =" Photo de profil Google ">
'
'Connectez - Out"http://realpython.com/.format( utilisateur actuel.prénom, utilisateur actuel.email, utilisateur actuel.photo de profil ) ) autre: revenir 'Connexion Google'

Vous remarquerez que vous renvoyez du HTML en tant que chaîne, que Flask pourra servir. le current_user.is_authenticated est une belle addition de la Flask-Login bibliothèque. C’est un moyen simple de déterminer si l’utilisateur actuel qui interagit avec votre application est connecté ou non. Cela vous permet d'appliquer une logique conditionnelle. Dans ce cas, il affiche certaines informations que vous avez enregistrées sur l’utilisateur, s’il est connecté.

Vous pouvez obtenir des champs de votre entrée de base de données pour l'utilisateur en y accédant simplement en tant qu'attributs sur utilisateur actuel objet, tel que current_user.email. Ceci est un autre ajout de Flask-Login.

S'identifier

Passons maintenant au flux OAuth 2. le Connexion Google Le bouton ci-dessus redirigera vers ce point de terminaison. La première étape du processus consiste à déterminer où se trouve le point de terminaison Autorisation OAuth 2 de Google.

C’est ici que les lignes entre ce qui est défini par OAuth 2 et par OpenID Connect (OIDC) commencent à s’estomper. Comme discuté précédemment, l'OIDC dispose d'un terminal standard pour une configuration du fournisseur, qui contient un tas d’informations OAuth 2 et OIDC. Le document contenant ces informations est diffusé à partir d’un point de terminaison standard partout, .bien-connu / openid-configuration.

En supposant que vous ayez copié le code précédent qui a défini GOOGLE_DISCOVERY_URL, voici une fonction rapide et naïve permettant de récupérer la configuration du fournisseur de Google:

def get_google_provider_cfg():
    revenir demandes.obtenir(GOOGLE_DISCOVERY_URL).JSON()

Le champ du document de configuration du fournisseur dont vous avez besoin s'appelle autorisation_endpoint. Il contiendra l'URL que vous devez utiliser pour lancer le flux OAuth 2 avec Google à partir de votre application client.

Vous pouvez mettre toute cette logique avec le code suivant:

@app.route("/login"http://realpython.com/)
def s'identifier():
    # Découvrez l'URL à utiliser pour la connexion à Google.
    google_provider_cfg = get_google_provider_cfg()
    autorisation_endpoint = google_provider_cfg[[[["authorisation_endpoint" http://realpython.com/]

    # Utiliser la bibliothèque pour créer la demande de connexion à Google et fournir
    # portées permettant de récupérer le profil de l'utilisateur sur Google
    request_uri = client.prepare_request_uri(
        autorisation_endpoint,
        redirect_uri=demande.base_url + "/callback"http://realpython.com/,
        portée=[[[["openid" http://realpython.com/, "email" http://realpython.com/, "profil" http://realpython.com/],
    )
    revenir réorienter(request_uri)

Heureusement, oauthlib facilite la demande à Google. Vous avez utilisé votre préconfiguré client que vous avez déjà donné à votre identifiant de client Google. Ensuite, vous avez fourni la redirection que vous souhaitez que Google utilise. Enfin, vous avez demandé à Google un numéro de OAuth 2 portée.

Vous pouvez considérer chaque étendue comme une information utilisateur distincte. Dans votre cas, vous demandez le courrier électronique de l’utilisateur et les informations de profil de base de Google. Bien entendu, l'utilisateur devra donner son consentement pour vous fournir ces informations.

Rappel de connexion

Faisons-le un par un, car il est un peu plus complexe que les quelques points de terminaison précédents.

Une fois que vous redirigez vers le point de terminaison des autorisations de Google, il se passe beaucoup de choses de la part de Google.

Le point de connexion de votre application est le point de départ de l’ensemble des travaux de Google, qui authentifie l’utilisateur et demande son consentement. Une fois que l'utilisateur s'est connecté à Google et qu'il accepte de partager son courrier électronique et les informations de son profil de base avec votre application, Google génère un code unique qu'il renvoie à votre application.

Pour rappel, voici les étapes de l'OIDC dont vous avez parlé plus tôt:

  1. Vous enregistrez une application tierce en tant que client du fournisseur.
  2. Le client envoie une demande au fournisseur du fournisseur. autorisation URL
  3. Le fournisseur demande à l'utilisateur de s'authentifier (prouver qui ils sont).
  4. Le fournisseur demande à l'utilisateur de consentir à ce que le client agisse en son nom.
  5. Le fournisseur envoie au client un code d'autorisation unique
  6. Le client renvoie le code d'autorisation à l'adresse du fournisseur. jeton URL
  7. Le fournisseur envoie les jetons client à utiliser avec d'autres URL pour le compte de l'utilisateur.

Lorsque Google renvoie ce code unique, il l'envoie à ce point de contact de rappel de connexion de votre application. Donc, votre première étape consiste à définir le point final et à l'obtenir code:

@app.route("/login/callback"http://realpython.com/)
def rappeler():
    # Obtenir le code d'autorisation que Google vous a renvoyé
    code = demande.args.obtenir("code" http://realpython.com/)

La prochaine chose que vous allez faire est de renvoyer ce code à Google. jeton point final. Une fois que Google a vérifié les informations d'identification de votre client, il vous renverra des jetons qui vous permettront de vous authentifier auprès d'autres noeuds finaux Google pour le compte de l'utilisateur, y compris le informations utilisateur point final que vous avez lu plus tôt. Dans votre cas, vous n’avez demandé qu’à afficher les informations de base sur votre profil. C’est la seule chose que vous puissiez faire avec les jetons.

Pour commencer, vous devez savoir ce que Google jeton le point final est. Vous utiliserez à nouveau le document de configuration du fournisseur:

# Découvrez l'URL à utiliser pour obtenir des jetons qui vous permettent de demander
# choses pour le compte d'un utilisateur
google_provider_cfg = get_google_provider_cfg()
token_endpoint = google_provider_cfg[[[["token_endpoint" http://realpython.com/]

oauthlib vient à votre secours à quelques reprises dans ce bloc de code suivant. Tout d'abord, vous devez créer la demande de jeton. Une fois la demande construite, vous utiliserez le demandes bibliothèque pour réellement l'envoyer. ensuite oauthlib, encore une fois, vous aidera à analyser les jetons de la réponse:

# Préparez et envoyez une demande pour obtenir des jetons! Yay jetons!
token_url, en-têtes, corps = client.prepare_token_request(
    token_endpoint,
    autorisation_réponse=demande.url,
    redirect_url=demande.base_url,
    code=code
)
token_response = demandes.poster(
    token_url,
    en-têtes=en-têtes,
    Les données=corps,
    auth=(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET),
)

# Analyser les jetons!
client.parse_request_body_response(JSON.décharges(token_response.JSON()))

Maintenant que vous disposez des outils nécessaires pour obtenir les informations de profil de l'utilisateur, vous devez les demander à Google. Heureusement, OIDC définit un point de terminaison d'informations utilisateur et son URL pour un fournisseur donné est normalisée dans la configuration du fournisseur. Vous pouvez obtenir l'emplacement en vérifiant la userinfo_endpoint champ dans le document de configuration du fournisseur. Ensuite, vous pouvez utiliser oauthlib ajouter le jeton à votre demande et utiliser demandes pour l'envoyer:

# Maintenant que vous avez des jetons (yay), trouvons et frappons l'URL
# de Google qui vous donne les informations de profil de l'utilisateur,
# y compris leur image de profil Google et leur email
userinfo_endpoint = google_provider_cfg[[[["userinfo_endpoint" http://realpython.com/]
uri, en-têtes, corps = client.add_token(userinfo_endpoint)
userinfo_response = demandes.obtenir(uri, en-têtes=en-têtes, Les données=corps)

La prochaine étape de votre parcours consiste à analyser la réponse du informations utilisateur point final. Google utilise un champ facultatif, Email verifié, pour confirmer que non seulement l’utilisateur a créé un compte, mais qu’il a également vérifié l’adresse électronique pour terminer la création du compte. Il est généralement prudent de vérifier cette vérification conditionnellement, car c’est un autre niveau de sécurité offert par Google.

Cela étant dit, vous allez vérifier cela et si Google dit que l'utilisateur est vérifié, vous analyserez ses informations. Les 4 informations de base sur le profil que vous utiliserez sont les suivantes:

  1. sous: le sujet, un identifiant unique pour l'utilisateur dans Google
  2. email: l'adresse e-mail Google de l'utilisateur
  3. image: la photo de profil public de l'utilisateur dans Google
  4. prénom: le prénom et le nom de l'utilisateur dans Google

Toute cette analyse aboutit au code suivant:

# Vous voulez vous assurer que leur email est vérifié.
# L'utilisateur authentifié avec Google, autorisé votre
# app, et maintenant vous avez vérifié leur email via Google!
si userinfo_response.JSON().obtenir("email_verified" http://realpython.com/):
    identifiant unique = userinfo_response.JSON()[[[["sub" http://realpython.com/]
    utilisateurs_email = userinfo_response.JSON()[[[["email" http://realpython.com/]
    image = userinfo_response.JSON()[[[["image" http://realpython.com/]
    nom_utilisateur = userinfo_response.JSON()[[[["prenom_nom" http://realpython.com/]
autre:
    revenir "Le courrier électronique de l'utilisateur n'est pas disponible ou n'a pas été vérifié par Google." Http://realpython.com/, 400

Les étapes finales de ce rappel sont les suivantes:

  1. Créez un utilisateur dans votre base de données avec les informations que vous venez de recevoir de Google.
  2. Commencez une session utilisateur en connectant cet utilisateur
  3. Renvoyer l'utilisateur à la page d'accueil (où vous allez maintenant afficher les informations de son profil public)

Le code pour accomplir ces étapes est le suivant:

# Créez un utilisateur dans votre base de données avec les informations fournies
# par Google
utilisateur = Utilisateur(
    id_=identifiant unique, prénom=nom_utilisateur, email=utilisateurs_email, photo de profil=image
)

# N'existe pas? Ajoutez-le à la base de données.
si ne pas Utilisateur.obtenir(identifiant unique):
    Utilisateur.créer(identifiant unique, nom_utilisateur, utilisateurs_email, image)

# Commencer la session utilisateur en le connectant à
login_user(utilisateur)

# Renvoyer l'utilisateur à la page d'accueil
revenir réorienter(url_for("index" http://realpython.com/))

Vous créez donc une nouvelle ligne dans votre base de données pour l'utilisateur, si celle-ci n'existe pas déjà. Ensuite, vous démarrez une session en utilisant Flask-Login.

Connectez – Out

Le point final de déconnexion contient beaucoup moins de code que les derniers points finaux. Vous appelez simplement une fonction de déconnexion et redirigez la page d'accueil. Fait et fait. C'est ici:

@app.route("/logout"http://realpython.com/)
@Connexion requise
def Connectez - Out():
    logout_user()
    revenir réorienter(url_for("index" http://realpython.com/))

le @Connexion requise décorateur est quelque chose d'important à mentionner ici. C’est un autre outil de la Flask-Login toolbox et s’assurera que seuls les utilisateurs connectés peuvent accéder à ce noeud final. Vous pouvez l'utiliser si seuls les utilisateurs connectés doivent accéder à quelque chose. Dans ce cas, seuls les utilisateurs connectés peuvent se déconnecter.

Tester votre application localement

Vous pouvez exécuter votre application Flask sur votre ordinateur local pour tester le flux de connexion en ajoutant du code final à app.py:

si __prénom__ == "__main__" http://realpython.com/:
    app.courir(ssl_context="adhoc" http://realpython.com/)

Vous pouvez exécuter votre application Flask avec la commande suivante dans votre terminal:

Flask doit imprimer sur votre terminal où il exécute le serveur de développement. CA devrait etre https://127.0.0.1:5000/.

Notez que le serveur de développement de Flask s'exécute localement et en utilisant https assurer une connexion cryptée avec Google. Ceci est réalisé par le ssl_context = "adhoc" argument à app.run dans le code ci-dessus. Cela nécessite que vous ayez le paquet PyOpenSSL installée.

L'inconvénient est que le certificat utilisé est généré à la volée, donc quand vous allez à https://127.0.0.1:5000/ dans votre navigateur, vous obtiendrez probablement un grand écran d’avertissement indiquant que votre connexion est non sécurisée ou non privée. Vous pouvez effectivement ignorer ces avertissements.

Une fois passé l’écran d’avertissement, vous devriez voir un seul bouton qui dit: Connexion Google. En appuyant dessus, vous serez redirigé vers le compte Google officiel. Une fois que vous vous êtes connecté, Google vous invite à donner votre consentement pour que l'application tierce puisse accéder à votre adresse électronique et à vos informations de profil.

Après avoir donné votre accord, vous serez redirigé vers votre application Flask, où la page devrait afficher votre adresse e-mail Google et votre photo de profil publique! Enfin, un Connectez – Out Ce bouton vous permet de vous déconnecter.

Conclusion

Autoriser les utilisateurs à utiliser leurs comptes existants pour se connecter à votre application Web présente de nombreux avantages. Plus important encore, la sécurité et la complexité de la gestion des comptes ne doivent pas reposer sur vos épaules. Cela vous libère pour écrire votre nouvelle application Web sophistiquée sans vous soucier des détails de base de l'authentification à deux facteurs, etc.

L’application que vous avez faite dans cet article est un excellent point de départ. Vous pouvez cliquer sur la case ci-dessous pour obtenir le code:

Votre prochaine étape pourrait être de faire ce qui suit:

  • Retravaillez l'initialisation de la base de données pour qu'elle se fasse séparément de l'exécution de l'application
  • Séparez le code HTML / CSS du code Python pour une gestion plus facile:
  • Hébergez votre application dans le cloud
  • Acheter un nom de domaine
  • Utiliser un vrai certificat SSL et se débarrasser de cet avertissement embêtant

Dans cet article, vous avez étudié les bases de OAuth 2 et OpenID Connect. Vous avez vu comment utiliser des packages Python connus pour créer une application Web permettant aux utilisateurs de se connecter avec leur compte Google existant. Most importantly, you have example code that serves as a great starting point for your next web application!