Freigeben über


Lernprogramm: Hinzufügen der Anmeldung zu einer Python Flask-Web-App

Dieses Lernprogramm ist der dritte Teil einer Lernprogrammreihe, in der das Erstellen einer Python Flask-Web-App von Grund auf und die Integration der Authentifizierung mithilfe der Microsoft Identity Platform veranschaulicht wird. In diesem Lernprogramm fügen Sie Code zur Authentifizierung von Benutzern in der app hinzu, die Sie erstellt haben.

  • Importieren der erforderlichen Module und Konfiguration
  • Erstellen einer Instanz einer Flask-Web-App
  • Konfigurieren der ProxyFix-Middleware für die lokale Entwicklung
  • Hinzufügen von Code zum Anmelden und Abmelden von Benutzern
  • Definieren eines Einstiegspunkts für die Web-App

Importieren erforderlicher Pakete und Konfigurationen

Die Web-App, die Sie erstellen, verwendet das identity.web Paket, das auf MSAL Python basiert, um Benutzer in Web-Apps zu authentifizieren. Um das identity.web-Paket, flask-Framework, Flask-Module, Flask-Sitzung und die im vorherigen Lernprogramm definierten App-Konfigurationen zu importieren, fügen Sie dem app.pyden folgenden Code hinzu:

import identity.web
import requests
from flask import Flask, redirect, render_template, request, session, url_for
from flask_session import Session

import app_config

In diesem Codeausschnitt importieren Sie die redirect, render_template, request, sessionund url_for: Funktionen und Objekte für die Verarbeitung von Webanforderungen und Sitzungen in Flask. Sie importieren auch app_config, das die Konfigurationseinstellungen für Ihre App enthält.

Erstellen einer Instanz der Flask-Web-App

Nach dem Importieren der erforderlichen Module initialisieren wir die Web-App mithilfe der Konfigurationen in app-config. Fügen Sie zum Erstellen einer Instanz Ihrer Web-App den folgenden Codeausschnitt zu app.pyhinzu:

app = Flask(__name__)
app.config.from_object(app_config)
assert app.config["REDIRECT_PATH"] != "/", "REDIRECT_PATH must not be /"
Session(app)

Im obigen Codeausschnitt initialisieren Sie eine neue Flask-Anwendung und laden die Konfigurationseinstellungen mithilfe von app.config.from_object(app_config). Mithilfe von from_objecterbt die App die Konfigurationen von der in (app_config)angegebenen.

Außerdem führen Sie eine Assertionsprüfung durch, um sicherzustellen, dass der Umleitungspfad Ihrer App nicht auf den Stammpfad ("/") festgelegt ist. Session(app) initialisiert die Sitzungsverwaltung für Ihre App, mit der Sie Sitzungen verarbeiten und Daten wie Benutzerauthentifizierungszustände über mehrere Anforderungen hinweg speichern können.

Konfigurieren der ProxyFix-Middleware für die lokale Entwicklung

Da die Beispielweb-App auf dem lokalen Host ausgeführt wird, verwenden wir die ProxyFix Middleware, um das URL-Schema und die Hostinformationen in den Anforderungsheadern zu beheben. Fügen Sie den folgenden Code zu app.py hinzu, um ProxyFix anzuwenden:

from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)

Initialisieren eines Authentifizierungsobjekts

Als Nächstes initialisieren Sie ein Authentifizierungsobjekt, indem Sie eine Instanz der identity.web.Auth-Klasse erstellen. Sie übergeben auch die Parameter session, authority, client_idund client_credential im Konstruktor beim Initialisieren des Auth-Objekts wie folgt:

app.jinja_env.globals.update(Auth=identity.web.Auth)  # Useful in template for B2C
auth = identity.web.Auth(
    session=session,
    authority=app.config["AUTHORITY"],
    client_id=app.config["CLIENT_ID"],
    client_credential=app.config["CLIENT_SECRET"],
)

In diesem Codeausschnitt fügt app.jinja_env.globals.update(Auth=identity.web.Auth)eine neue globale Variable mit dem Namen Auth hinzu und weist sie dem Wert identity.web.Authzu. Dadurch wird Authin allen Vorlagen barrierefrei, die von der Flask-Anwendung gerendert werden.

Anmelden von Benutzern

Der Autorisierungsfluss, den Sie in dieser App erstellen, besteht aus zwei Beinen. In der ersten Etappe rufen Sie die auth.log_in-Funktion zum Anmelden von Benutzern auf, wie gezeigt:

@app.route("/login")
def login():
    return render_template("login.html", version=__version__, **auth.log_in(
        scopes=app_config.SCOPE, # Have user consent to scopes during log-in
        redirect_uri=url_for("auth_response", _external=True), # Optional. If present, this absolute URL must match your app's redirect_uri registered in Microsoft Entra admin center
        prompt="select_account",  # Optional.
        ))

Wenn ein Benutzer zu der /login-URL in Ihrer App navigiert, ruft Flask die Ansichtsfunktion auf, die die Anforderung verarbeitet, um die login.html Vorlage zu rendern. Innerhalb login()rufen Sie die auth.log_in-Funktion mit einer Liste von Bereichen auf, denen der Benutzer während des Anmeldevorgangs zustimmen sollte. Außerdem stellen Sie das redirect_uri-Element in den Parametern bereit. Dieses Element sollte mit dem Umleitungs-URI der App im Microsoft Azure Admin Center übereinstimmen.

Sie können optional Parameter wie prompthinzufügen, die das Verhalten der Anmeldeaufforderung steuern, indem Sie eine erneute Authentifizierung, Benutzerzustimmung oder Kontoauswahl zwischen Konten mit aktiven Sitzungen anfordern.

Im zweiten Teil des Autorisierungsflusses behandeln Sie die Authentifizierungsantwort, indem Sie die auth.complete_log_in-Funktion innerhalb des redirect_uri-Controllers aufrufen, wie gezeigt:

@app.route(app_config.REDIRECT_PATH)
def auth_response():
    result = auth.complete_log_in(request.args)
    if "error" in result:
        return render_template("auth_error.html", result=result)
    return redirect(url_for("index"))

Die complete_log_in()-Funktion übernimmt das eingehende auth_response Wörterbuch als Abfrageparameter. Bei erfolgreicher Ausführung leitet die Funktion den Benutzer mithilfe von redirect(url_for("index"))zur "Index"-Route um. Dies bedeutet, dass der Benutzer sich erfolgreich angemeldet hat und seine Informationen in Form eines Wörterbuchs verfügbar sind, das Ansprüche aus einem bereits validierten ID-Token enthält.

Wenn das Ergebnis einen Fehler enthält, der durch die Bedingung if "error" in result:bestimmt wird, rendern Sie die "auth_error.html" Vorlage für den Benutzer.

Abmelden von Benutzern

Um Benutzer von Ihrer Flask-Anwendung abzumelden, rufen Sie die auth.log_out()-Methode wie folgt auf:

@app.route("/logout")
def logout():
    return redirect(auth.log_out(url_for("index", _external=True)))

Wenn ein Benutzer zur /logout URL-Route in der App navigiert, ruft Flask die Abmeldefunktion auf, die sie von der aktuellen App abmeldet. Sie geben auch die Seite an, zu der Benutzer bei der Abmeldung umgeleitet werden sollen. Im Codeausschnitt leiten wir Benutzer mithilfe von url_for("index", _external=True). zur Startseite der App um.

Definieren eines Einstiegspunkts für die Web-App

Fügen Sie nach der Implementierung der Anmelde- und Abmeldelogik einen Einstiegspunkt zur Startseite Ihrer App hinzu, indem Sie die index()-Funktion wie folgt erstellen:

@app.route("/")
def index():
    if not (app.config["CLIENT_ID"] and app.config["CLIENT_SECRET"]):
        # This check is not strictly necessary.
        # You can remove this check from your production code.
        return render_template('config_error.html')
    if not auth.get_user():
        return redirect(url_for("login"))
    return render_template('index.html', user=auth.get_user(), version=__version__)

Die index()-Funktion wird aufgerufen, wenn ein Benutzer zur Stamm-URL der App navigiert("/"). Er verarbeitet Konfigurationsprüfungen und überprüft die Benutzerauthentifizierung, bevor die Startseite der App gerendert wird. Es überprüft, ob die Client-ID und der geheime Clientschlüssel in der Konfiguration fehlen und ob entweder oder beide Werte fehlen, rendert Flask die "config_error.html" Vorlage.

Die Funktion ruft auch auth.get_user() auf, um zu überprüfen, ob der Benutzer authentifiziert ist oder nicht. Wenn der Benutzer nicht authentifiziert ist, leitet er ihn an die "login" Route weiter. Bei Authentifizierung rendert Flask die Vorlage "index.html" und übergibt das Benutzerobjekt (abgerufen aus auth.get_user()) zum Rendern.

Nächste Schritte