Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Viktigt!
Från och med den 1 maj 2025 är Azure AD B2C inte längre tillgängligt att köpa för nya kunder. Läs mer i våra vanliga frågor och svar.
I den här artikeln får du lära dig hur du lägger till Azure Active Directory B2C-autentisering (Azure AD B2C) i ditt eget Python-webbprogram. Du gör det möjligt för användare att logga in, logga ut, uppdatera profil och återställa lösenord med hjälp av Azure AD B2C-användarflöden. Den här artikeln använder Microsoft Authentication Library (MSAL) för Python för att förenkla tillägg av autentisering i python-webbprogrammet.
Syftet med den här artikeln är att ersätta exempelprogrammet som du använde i Konfigurera autentisering i ett Python-exempelwebbprogram med hjälp av Azure AD B2C med ditt eget Python-program.
Den här artikeln använder Python 3.9+ och Flask 2.1 för att skapa en grundläggande webbapp. Programmets vyer använder Jinja2-mallar.
Förutsättningar
- Slutför stegen i Konfigurera autentisering i ett Python-exempelwebbprogram med hjälp av Azure AD B2C. Du skapar Azure AD B2C-användarflöden och registrerar ett webbprogram i Azure-portalen.
- Installera Python 3.9 eller senare
- Visual Studio Code eller någon annan kodredigerare
- Installera Python-tillägget för Visual Studio Code
Steg 1: Skapa Python-projektet
I filsystemet skapar du en projektmapp för den här självstudien, till exempel
my-python-web-app.I terminalen ändrar du katalogen till python-appmappen, till exempel
cd my-python-web-app.Kör följande kommando för att skapa och aktivera en virtuell miljö med namnet
.venvbaserat på den aktuella tolken.Uppdatera pip i den virtuella miljön genom att köra följande kommando i terminalen:
python -m pip install --upgrade pipOm du vill aktivera Flask-felsökningsfunktionerna växlar du Flask till utvecklingsmiljö
developmentläge. Mer information om felsökning av Flask-appar finns i Flask-dokumentationen.Öppna projektmappen i VS Code genom att köra
code .kommandot eller genom att öppna VS Code och välja mappen Öppna fil>.
Steg 2: Installera beroenden för appen
Under rotmappen för webbappen skapar du requirements.txt filen. Kravfilen visar de paket som ska installeras med pip-installationen. Lägg till följande innehåll i filen requirements.txt:
Flask>=2
werkzeug>=2
flask-session>=0.3.2,<0.5
requests>=2,<3
msal>=1.7,<2
Installera beroendena i terminalen genom att köra följande kommandon:
Steg 3: Skapa appgränssnittskomponenter
Flask är ett enkelt Python-ramverk för webbprogram som tillhandahåller grunderna för URL-routning och sidåtergivning. Den använder Jinja2 som mallmotor för att återge innehållet i din app. Mer information finns i malldesignerdokumentationen. I det här avsnittet lägger du till de mallar som krävs som tillhandahåller de grundläggande funktionerna i webbappen.
Steg 3.1 Skapa en basmall
En bassidemall i Flask innehåller alla delade delar av en uppsättning sidor, inklusive referenser till CSS-filer, skriptfiler och så vidare. Basmallar definierar också en eller flera blocktaggar som andra mallar som utökar basen förväntas åsidosätta. En blocktagg avgränsas av {% block <name> %} och {% endblock %} i både basmallen och den utökade mallen.
Skapa mappen i webbappens templates rotmapp. I mappen templates skapar du en fil med namnet base.htmloch lägger sedan till innehållet nedan:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
{% block metadata %}{% endblock %}
<title>{% block title %}{% endblock %}</title>
<!-- Bootstrap CSS file reference -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.2.0-beta1/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-0evHe/X+R7YkIZDRvuzKMRqM+OrBnVFBL6DOitfPri4tjfHxaWutUpFmBp4vmVor" crossorigin="anonymous">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
<div class="container-fluid">
<a class="navbar-brand" href="{{ url_for('index')}}">Python Flask demo</a>
<button class="navbar-toggler" type="button" data-bs-toggle="collapse"
data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false"
aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="{{ url_for('index')}}">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="{{ url_for('graphcall')}}">Graph API</a>
</li>
</ul>
</div>
</div>
</nav>
<div class="container body-content">
<br />
{% block content %}
{% endblock %}
<hr />
<footer>
<p>Powered by MSAL Python {{ version }}</p>
</footer>
</div>
</body>
</html>
Steg 3.2 Skapa webbappmallarna
Lägg till följande mallar under mappen mallar. Mallarna utökar mallen base.html :
index.html: webbappens startsida. Mallarna använder följande logik: om en användare inte loggar in återges inloggningsknappen. Om en användare loggar in återger den åtkomsttokenens anspråk, och länk för att redigera profilen och anropar ett Graph API.
{% extends "base.html" %} {% block title %}Home{% endblock %} {% block content %} <h1>Microsoft Identity Python Web App</h1> {% if user %} <h2>Claims:</h2> <pre>{{ user |tojson(indent=4) }}</pre> {% if config.get("ENDPOINT") %} <li><a href='/graphcall'>Call Microsoft Graph API</a></li> {% endif %} {% if config.get("B2C_PROFILE_AUTHORITY") %} <li><a href='{{_build_auth_code_flow(authority=config["B2C_PROFILE_AUTHORITY"])["auth_uri"]}}'>Edit Profile</a></li> {% endif %} <li><a href="/logout">Logout</a></li> {% else %} <li><a href='{{ auth_url }}'>Sign In</a></li> {% endif %} {% endblock %}graph.html: Visar hur du anropar ett REST API.
{% extends "base.html" %} {% block title %}Graph API{% endblock %} {% block content %} <a href="javascript:window.history.go(-1)">Back</a> <!-- Displayed on top of a potentially large JSON response, so it will remain visible --> <h1>Graph API Call Result</h1> <pre>{{ result |tojson(indent=4) }}</pre> <!-- Just a generic json viewer --> {% endblock %}auth_error.html: Hanterar autentiseringsfel.
{% extends "base.html" %} {% block title%}Error{% endblock%} {% block metadata %} {% if config.get("B2C_RESET_PASSWORD_AUTHORITY") and "AADB2C90118" in result.get("error_description") %} <!-- See also https://learn.microsoft.com/azure/active-directory-b2c/active-directory-b2c-reference-policies#linking-user-flows --> <meta http-equiv="refresh" content='0;{{_build_auth_code_flow(authority=config["B2C_RESET_PASSWORD_AUTHORITY"])["auth_uri"]}}'> {% endif %} {% endblock %} {% block content %} <h2>Login Failure</h2> <dl> <dt>{{ result.get("error") }}</dt> <dd>{{ result.get("error_description") }}</dd> </dl> <a href="{{ url_for('index') }}">Homepage</a> {% endblock %}
Steg 4: Konfigurera webbappen
I rotmappen för webbappen skapar du en fil med namnet app_config.py. Den här filen innehåller information om din Azure AD B2C-identitetsprovider. Webbappen använder den här informationen för att upprätta en förtroenderelation med Azure AD B2C, logga in och ut användare, hämta token och verifiera dem. Lägg till följande innehåll i filen:
import os
b2c_tenant = "fabrikamb2c"
signupsignin_user_flow = "B2C_1_signupsignin1"
editprofile_user_flow = "B2C_1_profileediting1"
resetpassword_user_flow = "B2C_1_passwordreset1" # Note: Legacy setting.
authority_template = "https://{tenant}.b2clogin.com/{tenant}.onmicrosoft.com/{user_flow}"
CLIENT_ID = "Enter_the_Application_Id_here" # Application (client) ID of app registration
CLIENT_SECRET = "Enter_the_Client_Secret_Here" # Application secret.
AUTHORITY = authority_template.format(
tenant=b2c_tenant, user_flow=signupsignin_user_flow)
B2C_PROFILE_AUTHORITY = authority_template.format(
tenant=b2c_tenant, user_flow=editprofile_user_flow)
B2C_RESET_PASSWORD_AUTHORITY = authority_template.format(
tenant=b2c_tenant, user_flow=resetpassword_user_flow)
REDIRECT_PATH = "/getAToken"
# This is the API resource endpoint
ENDPOINT = '' # Application ID URI of app registration in Azure portal
# These are the scopes you've exposed in the web API app registration in the Azure portal
SCOPE = [] # Example with two exposed scopes: ["demo.read", "demo.write"]
SESSION_TYPE = "filesystem" # Specifies the token cache should be stored in server-side session
Uppdatera koden ovan med dina Azure AD B2C-miljöinställningar enligt beskrivningen i avsnittet Konfigurera exempelwebbappeni artikeln Konfigurera autentisering i en Python-exempelwebbapp .
Steg 5: Lägg till webbappkoden
I det här avsnittet lägger du till flaskvyfunktionerna och autentiseringsmetoderna för MSAL-biblioteket. Under rotmappen för projektet lägger du till en fil med namnet app.py med följande kod:
import uuid
import requests
from flask import Flask, render_template, session, request, redirect, url_for
from flask_session import Session # https://pythonhosted.org/Flask-Session
import msal
import app_config
app = Flask(__name__)
app.config.from_object(app_config)
Session(app)
# This section is needed for url_for("foo", _external=True) to automatically
# generate http scheme when this sample is running on localhost,
# and to generate https scheme when it is deployed behind reversed proxy.
# See also https://flask.palletsprojects.com/en/1.0.x/deploying/wsgi-standalone/#proxy-setups
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)
@app.route("/anonymous")
def anonymous():
return "anonymous page"
@app.route("/")
def index():
#if not session.get("user"):
# return redirect(url_for("login"))
if not session.get("user"):
session["flow"] = _build_auth_code_flow(scopes=app_config.SCOPE)
return render_template('index.html', auth_url=session["flow"]["auth_uri"], version=msal.__version__)
else:
return render_template('index.html', user=session["user"], version=msal.__version__)
@app.route("/login")
def login():
# Technically we could use empty list [] as scopes to do just sign in,
# here we choose to also collect end user consent upfront
session["flow"] = _build_auth_code_flow(scopes=app_config.SCOPE)
return render_template("login.html", auth_url=session["flow"]["auth_uri"], version=msal.__version__)
@app.route(app_config.REDIRECT_PATH) # Its absolute URL must match your app's redirect_uri set in AAD
def authorized():
try:
cache = _load_cache()
result = _build_msal_app(cache=cache).acquire_token_by_auth_code_flow(
session.get("flow", {}), request.args)
if "error" in result:
return render_template("auth_error.html", result=result)
session["user"] = result.get("id_token_claims")
_save_cache(cache)
except ValueError: # Usually caused by CSRF
pass # Simply ignore them
return redirect(url_for("index"))
@app.route("/logout")
def logout():
session.clear() # Wipe out user and its token cache from session
return redirect( # Also logout from your tenant's web session
app_config.AUTHORITY + "/oauth2/v2.0/logout" +
"?post_logout_redirect_uri=" + url_for("index", _external=True))
@app.route("/graphcall")
def graphcall():
token = _get_token_from_cache(app_config.SCOPE)
if not token:
return redirect(url_for("login"))
graph_data = requests.get( # Use token to call downstream service
app_config.ENDPOINT,
headers={'Authorization': 'Bearer ' + token['access_token']},
).json()
return render_template('graph.html', result=graph_data)
def _load_cache():
cache = msal.SerializableTokenCache()
if session.get("token_cache"):
cache.deserialize(session["token_cache"])
return cache
def _save_cache(cache):
if cache.has_state_changed:
session["token_cache"] = cache.serialize()
def _build_msal_app(cache=None, authority=None):
return msal.ConfidentialClientApplication(
app_config.CLIENT_ID, authority=authority or app_config.AUTHORITY,
client_credential=app_config.CLIENT_SECRET, token_cache=cache)
def _build_auth_code_flow(authority=None, scopes=None):
return _build_msal_app(authority=authority).initiate_auth_code_flow(
scopes or [],
redirect_uri=url_for("authorized", _external=True))
def _get_token_from_cache(scope=None):
cache = _load_cache() # This web app maintains one cache per session
cca = _build_msal_app(cache=cache)
accounts = cca.get_accounts()
if accounts: # So all account(s) belong to the current signed-in user
result = cca.acquire_token_silent(scope, account=accounts[0])
_save_cache(cache)
return result
app.jinja_env.globals.update(_build_auth_code_flow=_build_auth_code_flow) # Used in template
if __name__ == "__main__":
app.run()
Steg 6: Kör din webbapp
I terminalen kör du appen genom att ange följande kommando, som kör Flask-utvecklingsservern. Utvecklingsservern söker app.py som standard. Öppna sedan webbläsaren och gå till webbappens URL: http://localhost:5000.
[Valfritt] Felsöka din app
Felsökningsfunktionen ger dig möjlighet att pausa ett program som körs på en viss kodrad. När du pausar programmet kan du undersöka variabler, köra kod i panelen Felsökningskonsol och på annat sätt dra nytta av de funktioner som beskrivs i Felsökning. Om du vill använda Felsökningsprogrammet för Visual Studio Code kan du läsa dokumentationen för VS Code.
Om du vill ändra värdnamnet och/eller portnumret använder du args filens launch.json matris. I följande exempel visas hur du konfigurerar värdnamnet till localhost och portnumret till 5001. Observera att om du ändrar värdnamnet eller portnumret måste du uppdatera omdirigerings-URI:n eller ditt program. Mer information finns i steget Registrera ett webbprogram .
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: Flask",
"type": "python",
"request": "launch",
"module": "flask",
"env": {
"FLASK_APP": "app.py",
"FLASK_ENV": "development"
},
"args": [
"run",
"--host=localhost",
"--port=5001"
],
"jinja": true,
"justMyCode": true
}
]
}