Créer une application Flask avec Google Login

Créer une application Flask avec Google Login

Vous avez probablement vu l'option pourGoogle Login sur divers sites Web. Certains sites ont également plus d'options commeFacebook Login ouGitHub Login. Toutes ces options permettent aux utilisateurs d'utiliser les comptes existants pour utiliser un nouveau service.

Dans cet article, vous allez travailler à la création d'une application WebFlask. Votre application permettra à un utilisateur de se connecter en utilisant son identité Google au lieu de créer un nouveau compte. Il y a des tonnes d'avantages avec cette méthode de gestion des utilisateurs. Cela sera plus sûr et plus simple 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à lesbasics of Python. Il serait également utile d'en savoir un peu plus sur les cadres Web et les requêtes HTTP, mais ce n'est pas strictement nécessaire.

À la fin de cet article, vous serez en mesure de:

  • Créer une application Web Flask qui permet aux utilisateurs de se connecter avec Google

  • Créer des informations d'identification client pour interagir avec Google

  • Utiliser Flask-Login pour la gestion des sessions 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 pouvez souhaiter que les utilisateurs individuels aient des profils. Ou peut-être souhaitez-vous fournir 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 d'une manière unique.

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

  • Vous devez gérer en toute sécurité les mots de passe.

  • Vous devez implémenter toute fonctionnalité liée au compte:

    • Authentification à deux facteurs

    • Réinitialisation du 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 imposez 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 gère toute la sécurité.

Comment les applications utilisent Google Login

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

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

Vous êtes sur le point d'écrire une application tierce et elle permettra à un utilisateur d'utiliser un boutonGoogle Login pour se connecter. Pour ce faire, Google doit connaître votre application. Heureusement, vous pouvez enregistrer votre application en tant que client auprès de Google.

Une fois qu'un utilisateur accède à votre application et appuie sur le boutonGoogle Login, vous pouvez l'envoyer à Google. À partir de là, Google doit s'assurer que l'utilisateur consent à transmettre son e-mail 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 plus tard, connectant efficacement l'utilisateur.

Détails d'OpenID Connect

Pour demander des informations au nom d'un utilisateur, vous devez devenir unclient auprès du serveur d'authentification, également appelé fournisseur. La première chose que vous réaliserez si vous creusez dans ces spécifications est qu'il y a beaucoup de termes et de concepts qui se chevauchent.

Par conséquent, en tant qu'application tierce (également appelée client), vous souhaitez obtenir des informations du fournisseur au nom de l'utilisateur. Il existe une série d'étapes qui permettent que cela se produise, et ces étapes doivent se produire dans un ordre spécifique. C'est pourquoi vous entendrez parfois OAuth 2 et OpenID Connect appeléshandshake,flow oudance.

Ces étapes sont, en gros:

  1. Vous enregistrez une application tierce en tant que client auprès du fournisseur:

    • Vous recevez les 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 à l'URLauthorizationdu fournisseur

  3. Le fournisseur demande à l'utilisateur de s'authentifier (prouver qui il est)

  4. Le prestataire demande à l'utilisateur de consentir à ce que le client agisse en son nom:

    • Habituellement, cela inclut un accès limité et il est clair pour l'utilisateur ce que le client demande.

    • C'est comme lorsque vous devez approuver une application sur votre téléphone pour avoir accès à 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'URLtokendu fournisseur.

  7. Le fournisseur envoie les jetons client à utiliser avec d'autres URL de fournisseur au nom de l'utilisateur.

Note: Les étapes ci-dessus concernent le flux de code d'autorisation, tel que défini par OAuth 2.

Ces étapes incluent les deux normes mentionnées jusqu'à présent. OpenID Connect (OIDC) est construit 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 lesprovider configuration etuserinfo endpoint.

Leprovider configuration contient des informations sur le fournisseur, y compris les URL exactes que vous devez 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 avecstandardized fields.

Lesuserinfo endpoint renverront des informations sur l'utilisateur une fois que vous aurez parcouru le flux OAuth 2. Cela comprendra leur e-mail et certaines informations de profil de base que vous utiliserez dans votre application. Pour obtenir ces informations utilisateur, vous aurez besoin d'un jeton du fournisseur, comme décrit à la dernière étape du flux ci-dessus.

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

Création d'un client Google

La première étape pour activer une optionGoogle Login consiste à enregistrer votre application en tant que client auprès de Google. Parcourons 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.

Une fois entré, vous pouvez être invité à accepter leurs conditions d'utilisation. Si vous les acceptez, appuyez sur le boutonCreate credentials de la page suivante. Sélectionnez l'option pourOAuth client ID:

Google create credentials screen shot

Sélectionnez l'optionWeb application en haut. Vous pouvez également fournir un nom pour le client dans le champName. Le nom que vous fournissez sera affiché aux utilisateurs lorsqu'ils consentent à ce que votre application agisse en leur nom.

Vous exécuterez votre application Web localement pour le moment, vous pouvez donc définirAuthorized JavaScript origins surhttps://127.0.0.1:5000 etAuthorized redirect URIs surhttps://127.0.0.1:5000/login/callback. Cela permettra à votre application Flask locale de communiquer avec Google.

Enfin, appuyez surCreate et notez lesclient ID etclient secret. Vous aurez besoin des deux plus tard.

Création de votre propre application Web

Maintenant, pour la partie amusante où vous appliquez les connaissances que vous avez apprises pour créer une application Web réelle!

Commençons par le but en tête. Vous souhaitez créer une application qui permet aux utilisateurs de se connecter avec leur compte Google. Cette application devrait être en mesure de récupérer des informations de base sur l'utilisateur de Google, comme son adresse e-mail. Ensuite, l'application doit stocker les informations utilisateur de base dans une base de données.

Tout d'abord, examinons le cadre et les bibliothèques que vous utiliserez.

Ballon

Flask est un framework Web léger, unmicroframework auto-proclamé. Il est livré avec des outils intégrés pour les tâches de base qu'une application Web effectuera, comme 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 choses que vous avez apprises sur OAuth 2 et OIDC ne sont pas spécifiques à Flask. En fait, même la bibliothèque que vous utiliserez pour simplifier OAuth 2 et OIDC est utilisable dans n'importe quel code Python. En d'autres termes, avec quelques modifications mineures, vous pouvez prendre ce que vous apprenez ici et l'appliquer à un autre cadre de votre choix.

Flask-Login

Un autre outil que vous pouvez utiliser pour faciliter la gestion des utilisateurs estflask_login, qui fournituser session management.

Cette bibliothèque fait quelques choses en arrière-plan 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 de 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. Du point de vue de votre code, cela rend tout simplement beaucoup plus simple (ce que vous verrez bientôt).

OAuthLib

Il existe une expression courante qui s'applique tout à fait aux codes liés à la sécurité et aux normes: «Ne réinventez pas la roue».

Les normes OAuth 2 et OpenID Connect sont compliquées. Jetez un œil à la RFC et aux 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 certains critères très spécifiques:

  1. C'est une bibliothèque populaire et généralement recommandée. De nombreux autres packages utilisent cette bibliothèque en interne.

  2. Il est très actif, les gens corrigent fréquemment les bogues.

  3. Il est endurci au combat et existe depuis 2012.

Il existe des packages spécifiques au framework Web qui utilisent cette bibliothèque pour s'intégrer plus étroitement dans Flask, Django, Pyramid et autres. Cependant, pour conserver le code que vous apprenez ici indépendant du cadre, vous utiliserez cette bibliothèque directement sans aucun emballage sophistiqué.

Installation de dépendances

Il existe un certain nombre de dépendances tierces que vous utiliserez pour vous faciliter la vie. Voici un résumé de ces dépendances:

  • Un cadre Web pour faciliter les tâches d'application Web typiques (Flask)

  • Une façon sans maux de tête de gérer les sessions utilisateur (Flask-Login)

  • Une bibliothèque OIDC renforcée 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 (requests)

  • Un moyen rapide d'activer l'exécution en toute sécurité avechttps localement (pyOpenSSL)

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

Tout d'abord, vous devrez installer les dépendances tierces mentionnées ci-dessus. Pour ce faire, créez un fichierrequirements.txt avec le contenu suivant:

requests==2.21.0
Flask==1.0.2
oauthlib==3.0.1
pyOpenSSL==19.0.0
Flask-Login==0.4.1

Note: D'autres versions des packages peuvent fonctionner, mais ce sont des versions qui ont été utilisées lors de la rédaction et du test de cet article.

Ensuite, vous pouvez installer ces dépendances à l’aide depip, le programme d’installation de packages de Python.

Note: Il est généralement recommandé d'utiliser des environnements virtuels si vous prévoyez d'installer des dépendances pour différentes applications Python sur votre ordinateur. VoirPython Virtual Environments: A Primer pour en savoir plus.

Pour installer à partir du fichierrequirements.txt, exécutez la commande suivante dans votre terminal:

$ pip install -r requirements.txt

Vous êtes maintenant prêt à faire du rock and roll! Explorons le code.

Importations, configuration et installation

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 dePython database est un terrier qui nous détournerait de notre objectif.

Le fichierschema.sql est juste un SQL qui créera une table utilisateur dans notre base de données. Vous pouvez voir les champs que vous stockerez par utilisateur dans ce fichier.

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

Après avoir créé les fichiersdb.py,schema.sql etuser.py à partir du code ci-dessus, vous pouvez créer un nouveau fichierapp.py. Ajoutez-y les importations suivantes:

# Python standard libraries
import json
import os
import sqlite3

# Third-party libraries
from flask import Flask, redirect, request, url_for
from flask_login import (
    LoginManager,
    current_user,
    login_required,
    login_user,
    logout_user,
)
from oauthlib.oauth2 import WebApplicationClient
import requests

# Internal imports
from db import init_db_command
from user import User

Vous les utiliserez plus tard, il n'est donc pas si important de comprendre chacun d'eux pour le moment. La partie suivante de vosapp.py est une configuration:

# Configuration
GOOGLE_CLIENT_ID = os.environ.get("GOOGLE_CLIENT_ID", None)
GOOGLE_CLIENT_SECRET = os.environ.get("GOOGLE_CLIENT_SECRET", None)
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. Ceux-ci seront utilisés 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. Vous n'avez pas besoin de modifier votre code plus tard si vous souhaitez utiliser des informations d'identification différentes, il vous suffit de mettre à jour l'environnement.

  2. Vous ne pouvez pas accidentellement valider vos informations d'identification secrètes sur GitHub (ou un autre référentiel public).

De nombreuses personnes commettent accidentellement des secrets dans des référentiels publics, ce qui pose un risque de sécurité assez sérieux. Il vaut mieux se protéger contre cela en utilisant des variables environnementales.

Tip: Vous pouvez définir vos informations d'identification client comme variables d'environnement dans le terminal bash Linux et le terminal Mac OS X à l'aide deexport GOOGLE_CLIENT_ID=your_client_id (de même pourGOOGLE_CLIENT_SECRET).

Si vous utilisez Windows, vous pouvez utiliserset GOOGLE_CLIENT_ID=your_client_id dans l’invite de commandes.

Alternativement, vouscouldcollez les chaînes directement ici et les stockez dans ces variables. However, le secret client doitnot être partagé ou validé dans un référentiel public. En d'autres termes, faites très attention à ne pas archiver ce fichier si vous collez ici vos informations d'identification client réelles.

Enfin, ci-dessous est un code avec des variables globales et une logique d'initialisation de base de données naïve. La plupart de cela, à l'exception de l'initialisation de la base de données, est le moyen standard de configurer Flask, Flask-Login et OAuthLib, que vous avez lu plus tôt:

# Flask app setup
app = Flask(__name__)
app.secret_key = os.environ.get("SECRET_KEY") or os.urandom(24)

# User session management setup
# https://flask-login.readthedocs.io/en/latest
login_manager = LoginManager()
login_manager.init_app(app)

# Naive database setup
try:
    init_db_command()
except sqlite3.OperationalError:
    # Assume it's already been created
    pass

# OAuth 2 client setup
client = WebApplicationClient(GOOGLE_CLIENT_ID)

# Flask-Login helper to retrieve a user from our db
@login_manager.user_loader
def load_user(user_id):
    return User.get(user_id)

Notez que vous utilisez déjà l'ID client de Google pour initialiser notre clientoauthlib dans lesWebApplicationClient.

Vous pouvez créer une autre variable d'environnementSECRET_KEY queFlask and Flask-Login will use pour signer cryptographiquement les cookies et autres éléments.

Points de terminaison d'application 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 utilisateur

  3. Un pour un rappel vers lequel Google redirigera après la connexion d'un utilisateur

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

  3. Rappel de connexion: /login/callback

  4. Se déconnecter: /logout

Bien sûr, vous souhaiterez 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 allez ajouter tout le code suivant pour ces points de terminaison dans le fichierapp.py. Jetons un œil à chacun des codes de ces points de terminaison, un à la fois.

Page d'accueil

Cela n'a rien de sophistiqué visuellement, mais vous ajouterez une logique claire pour afficher quelque chose de différent si un utilisateur est connecté. Lorsqu'ils ne sont pas connectés, un lien apparaîtra indiquantGoogle Login.

Appuyer sur le lien les redirigera vers votre point de terminaison/login, ce qui lancera le flux de connexion. Après une connexion réussie, la page d'accueil affichera désormais à la fois l'e-mail Google de l'utilisateur et sa photo de profil Google publique!

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

@app.route("/")
def index():
    if current_user.is_authenticated:
        return (
            "

Hello, {}! You're logged in! Email: {}

" "

Google Profile Picture:

" 'Google profile pic
' 'Logout'.format( current_user.name, current_user.email, current_user.profile_pic ) ) else: return 'Google Login'

Vous remarquerez que vous retournez du code HTML sous forme de chaîne, que Flask pourra servir. Lecurrent_user.is_authenticated est un bel ajout à la bibliothèqueFlask-Login. 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 l'objetcurrent_user, tel quecurrent_user.email. Ceci est un autre ajout deFlask-Login.

S'identifier

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

Voici où les lignes entre ce qui est défini par OAuth 2 et par OpenID Connect (OIDC) commencent à s'estomper. Comme indiqué précédemment, OIDC a un point de terminaison standard pour unprovider configuration, qui contient un tas d'informations OAuth 2 et OIDC. Le document contenant ces informations est servi à partir d'un point de terminaison standard partout,.well-known/openid-configuration.

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

def get_google_provider_cfg():
    return requests.get(GOOGLE_DISCOVERY_URL).json()

Tip: Pour rendre cela plus robuste, vous devez ajouter la gestion des erreurs à l'appel d'API Google, juste au cas où l'API de Google renvoie un échec et non le document de configuration du fournisseur valide.

Le champ du document de configuration du fournisseur dont vous avez besoin est appeléauthorization_endpoint. Celui-ci contiendra l'URL que vous devez utiliser pour lancer le flux OAuth 2 avec Google à partir de votre application client.

Vous pouvez regrouper toute cette logique avec le code suivant:

@app.route("/login")
def login():
    # Find out what URL to hit for Google login
    google_provider_cfg = get_google_provider_cfg()
    authorization_endpoint = google_provider_cfg["authorization_endpoint"]

    # Use library to construct the request for Google login and provide
    # scopes that let you retrieve user's profile from Google
    request_uri = client.prepare_request_uri(
        authorization_endpoint,
        redirect_uri=request.base_url + "/callback",
        scope=["openid", "email", "profile"],
    )
    return redirect(request_uri)

Heureusement,oauthlib facilite la demande à Google. Vous avez utilisé vosclient préconfigurés auxquels vous avez déjà donné votre identifiant client Google. Ensuite, vous avez fourni la redirection que vous souhaitez que Google utilise. Enfin, vous avez demandé à Google un certain nombre de OAuth 2scopes.

Vous pouvez considérer chaque étendue comme une information distincte pour l'utilisateur. Dans votre cas, vous demandez l'adresse e-mail et les informations de base du profil de l'utilisateur à Google. L'utilisateur devra bien entendu consentir à vous communiquer ces informations.

Note:openid est une étendue requise pour indiquer à Google d'initier le flux OIDC, qui authentifiera l'utilisateur en lui faisant se connecter. OAuth 2 ne standardise pas réellement la façon dont l'authentification se produit, c'est donc nécessaire pour notre flux dans ce cas.

Rappel de connexion

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

Une fois que vous avez redirigé vers le point de terminaison d'autorisation de Google, il se passe beaucoup de choses du côté de Google.

Le point de terminaison de connexion sur votre application est le point de départ de tout le travail de Google authentifiant l'utilisateur et demandant son consentement. Une fois que l'utilisateur se connecte à Google et accepte de partager ses e-mails et ses informations de profil de base avec votre application, Google génère un code unique qu'il renvoie à votre application.

Pour rappel, voici les étapes OIDC que vous avez lues précédemment:

  1. Vous enregistrez une application tierce en tant que client auprès du fournisseur.

  2. Le client envoie une requête à l'URLauthorizationdu fournisseur.

  3. Le fournisseur demande à l'utilisateur de s'authentifier (prouver qui il est).

  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'URLtoken du fournisseur

  7. Le fournisseur envoie les jetons clients à utiliser avec d'autres URL au nom de l'utilisateur

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

@app.route("/login/callback")
def callback():
    # Get authorization code Google sent back to you
    code = request.args.get("code")

La prochaine chose que vous allez faire est de renvoyer ce code au point de terminaisontokende Google. 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 points de terminaison Google au nom de l'utilisateur, y compris le point de terminaisonuserinfo que vous avez lu précédemment. Dans votre cas, vous avez seulement demandé à afficher les informations de profil de base, c'est donc la seule chose que vous pouvez faire avec les jetons.

Pour commencer, vous devez déterminer quel est le point de terminaisontoken de Google. Vous utiliserez à nouveau le document de configuration du fournisseur:

# Find out what URL to hit to get tokens that allow you to ask for
# things on behalf of a user
google_provider_cfg = get_google_provider_cfg()
token_endpoint = google_provider_cfg["token_endpoint"]

oauthlib vient à votre secours plusieurs fois dans ce prochain bloc de code. Tout d'abord, vous devez créer la demande de jeton. Une fois la requête construite, vous utiliserez la bibliothèquerequests pour l’envoyer. Ensuite,oauthlib, une fois de plus, vous aidera à analyser les jetons de la réponse:

# Prepare and send a request to get tokens! Yay tokens!
token_url, headers, body = client.prepare_token_request(
    token_endpoint,
    authorization_response=request.url,
    redirect_url=request.base_url,
    code=code
)
token_response = requests.post(
    token_url,
    headers=headers,
    data=body,
    auth=(GOOGLE_CLIENT_ID, GOOGLE_CLIENT_SECRET),
)

# Parse the tokens!
client.parse_request_body_response(json.dumps(token_response.json()))

Maintenant que vous disposez des outils nécessaires pour obtenir les informations de profil de l'utilisateur, vous devez en faire la demande à 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 le champuserinfo_endpoint dans le document de configuration du fournisseur. Ensuite, vous pouvez utiliseroauthlib pour ajouter le jeton à votre demande et utiliserrequests pour l'envoyer:

# Now that you have tokens (yay) let's find and hit the URL
# from Google that gives you the user's profile information,
# including their Google profile image and email
userinfo_endpoint = google_provider_cfg["userinfo_endpoint"]
uri, headers, body = client.add_token(userinfo_endpoint)
userinfo_response = requests.get(uri, headers=headers, data=body)

La prochaine étape de votre parcours consiste à analyser la réponse du point de terminaisonuserinfo. Google utilise un champ facultatif,email_verified, pour confirmer que non seulement l'utilisateur a créé un compte, mais qu'il a également validé l'adresse e-mail pour terminer la création du compte. Il est généralement sûr de vérifier conditionnellement cette vérification, car il s'agit d'une autre couche de sécurité offerte 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:

  1. sub: le sujet, un identifiant unique pour l'utilisateur dans Google

  2. email: l'adresse e-mail Google de l'utilisateur

  3. picture: la photo de profil publique de l'utilisateur dans Google

  4. given_name: le prénom et le nom de l'utilisateur dans Google

Toutes ces analyses aboutissent au code suivant:

# You want to make sure their email is verified.
# The user authenticated with Google, authorized your
# app, and now you've verified their email through Google!
if userinfo_response.json().get("email_verified"):
    unique_id = userinfo_response.json()["sub"]
    users_email = userinfo_response.json()["email"]
    picture = userinfo_response.json()["picture"]
    users_name = userinfo_response.json()["given_name"]
else:
    return "User email not available or not verified by Google.", 400

Les dernières étapes 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 ses informations de profil public)

Le code pour accomplir ces étapes est le suivant:

# Create a user in your db with the information provided
# by Google
user = User(
    id_=unique_id, name=users_name, email=users_email, profile_pic=picture
)

# Doesn't exist? Add it to the database.
if not User.get(unique_id):
    User.create(unique_id, users_name, users_email, picture)

# Begin user session by logging the user in
login_user(user)

# Send user back to homepage
return redirect(url_for("index"))

Donc, ce que vous faites ici, c'est de créer une nouvelle ligne dans votre base de données pour l'utilisateur si elle n'existe pas déjà. Ensuite, vous démarrez une session à l'aide de Flask-Login.

Se déconnecter

Le point de terminaison de déconnexion est beaucoup moins de code que les derniers points de terminaison. Vous venez d'appeler une fonction de déconnexion et de rediriger vers la page d'accueil. Fait et fait. C'est ici:

@app.route("/logout")
@login_required
def logout():
    logout_user()
    return redirect(url_for("index"))

Le@login_requireddecorator est quelque chose d'important à mentionner ici. C'est un autre outil de la boîte à outils deFlask-Login et garantira que seuls les utilisateurs connectés peuvent accéder à ce point de terminaison. 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.

Test de 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:

if __name__ == "__main__":
    app.run(ssl_context="adhoc")

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

$ python app.py

Note: En raison de la logique naïve d'initialisation de la base de données, la première fois que vous exécutez cette commande, elle crée la base de données. Pour démarrer votre application, vous devez exécuter la même commandeagain.

Flask devrait imprimer sur votre terminal où il exécute le serveur de développement. Ce devrait êtrehttps://127.0.0.1:5000/.

Notez que le serveur de développement de Flask exécute localementand en utilisanthttps pour garantir une connexion chiffrée avec Google. Ceci est réalisé par l'argumentssl_context="adhoc" àapp.run dans le code ci-dessus. Cela nécessite que vous ayez installé le packagePyOpenSSL.

L'inconvénient est que le certificat utilisé est généré à la volée, donc lorsque vous accédez àhttps://127.0.0.1:5000/ dans votre navigateur, cela vous donnera probablement un grand écran d'avertissement indiquant que votre connexion n'est pas 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 indiquantGoogle Login. En appuyant dessus, vous serez redirigé vers la connexion Google officielle. Une fois connecté, Google vous demandera de consentir à ce que «l'application tierce» ait accès à vos e-mails et à vos informations de profil.

Après avoir consenti, vous serez redirigé vers votre application Flask, où la page devrait afficher votre adresse e-mail Google et votre photo de profil public! Enfin, un boutonLogout vous permet de vous déconnecter.

Conclusion

Permettre aux utilisateurs d'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 permet d'écrire votre nouvelle application Web de fantaisie sans vous soucier des détails de l'authentification à deux facteurs et autres.

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 procéder comme suit:

  • Retravailler l'initialisation de la base de données pour qu'elle se produise séparément de l'exécution de l'application

  • Séparez le HTML / CSS du code Python pour une gestion plus facile:

    • Vous pouvez utilisertemplates.

    • Vous pouvez également charger des fichiers statiques (comme JS et CSS)from elsewhere.

  • Hébergez votre application dans le cloud

  • Acheter un nom de domaine

  • Utilisez un vrai certificat SSL et débarrassez-vous de cet avertissement embêtant

Dans cet article, vous avez parcouru les bases d'OAuth 2 et d'OpenID Connect. Vous avez vu comment utiliser des packages Python bien connus pour créer une application Web qui permet aux utilisateurs de se connecter avec leur compte Google existant. Plus important encore, vous avez un exemple de code qui constitue un excellent point de départ pour votre prochaine application Web!