Tutorial: Agregar inicio de sesión a una aplicación web Python Flask
Este tutorial es la tercera parte de una serie de tutoriales que muestra cómo compilar una aplicación web de Python Flask desde cero e integrar la autenticación mediante la plataforma de identidad de Microsoft. En este tutorial, agregará código para autenticar a los usuarios en la aplicación que ha compilado.
- Importación de los módulos y la configuración necesarios
- Creación de una instancia de una aplicación web de Flask
- Configuración del middleware ProxyFix para el desarrollo local
- Agregar código para admitir el inicio y el cierre de sesión de usuarios
- Definición de un punto de entrada para la aplicación web
Importación de paquetes y configuraciones necesarios
La aplicación web que va a compilar usa el paquete de identity.web
basado en MSAL Python para autenticar a los usuarios en aplicaciones web. Para importar el paquete de identity.web
, el marco de Flask, los módulos de Flask, la sesión de Flask y las configuraciones de la aplicación definidas en el tutorial anterior, agregue el código siguiente a app.py:
import identity.web
import requests
from flask import Flask, redirect, render_template, request, session, url_for
from flask_session import Session
import app_config
En este fragmento de código, se importan los redirect
, render_template
, request
, session
y url_for
: funciones y objetos para controlar las solicitudes y sesiones web en Flask. También se importa app_config
, que contiene los valores de configuración de la aplicación.
Creación de una instancia de la aplicación web de Flask
Después de importar los módulos necesarios, inicializamos la aplicación web mediante las configuraciones en app-config
. Para crear una instancia de la aplicación web, agregue el siguiente fragmento de código a app.py
:
app = Flask(__name__)
app.config.from_object(app_config)
assert app.config["REDIRECT_PATH"] != "/", "REDIRECT_PATH must not be /"
Session(app)
En el fragmento de código anterior, inicializa una nueva aplicación de Flask y carga las opciones de configuración mediante app.config.from_object(app_config)
. Mediante from_object
, la aplicación hereda las configuraciones del especificado en (app_config)
.
También realiza una comprobación de aserción para asegurarse de que la ruta de acceso de redirección de la aplicación no está establecida en la ruta de acceso raíz (“/”). Session(app)
inicializa la administración de sesiones para la aplicación, lo que habilita controlar sesiones y almacenar datos como estados de autenticación de usuario en varias solicitudes.
Configuración del middleware ProxyFix para el desarrollo local
Dado que la aplicación web de ejemplo se ejecuta en el host local, usamos el ProxyFix
middleware para corregir el esquema de dirección URL y la información del host en los encabezados de solicitud. Agregue el código siguiente a app.py
para aplicar ProxyFix:
from werkzeug.middleware.proxy_fix import ProxyFix
app.wsgi_app = ProxyFix(app.wsgi_app, x_proto=1, x_host=1)
Inicialización de un objeto de autenticación
A continuación, inicializa un objeto de autenticación mediante la creación de una instancia de la clase [identity.web.Auth](https://identity-library.readthedocs.io/en/latest/#identity.web.Auth)
. También se pasan los parámetros session
, authority
, client_id
y client_credential
en el constructor al inicializar el objeto Auth, como se indica a continuación:
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"],
)
En este fragmento de código, app.jinja_env.globals.update(Auth=identity.web.Auth)
agrega una nueva variable global denominada Auth
y le asigna el valor de identity.web.Auth
. Esto hace que Auth
sea accesible en todas las plantillas representadas por la aplicación Flask.
Inicio de sesión de usuarios
El flujo de autorización que compila en esta aplicación consta de dos patas. En la primera fase, se invoca la función auth.log_in
para iniciar sesión a los usuarios, como se muestra a continuación:
@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.
))
Cuando un usuario navega a la dirección URL de /login
de la aplicación, Flask invoca la función de vista que controla la solicitud para representar la plantilla de login.html
. Dentro de login()
, se llama a la función auth.log_in
con una lista de ámbitos a los que el usuario debe dar su consentimiento durante el proceso de inicio de sesión. También proporciona redirect_uri
en los parámetros, que deben coincidir con el URI de redirección de la aplicación i el Centro de administración de Microsoft Azure.
Opcionalmente, puede agregar parámetros como prompt
, que controla el comportamiento del mensaje de inicio de sesión solicitando la reautenticación, el consentimiento del usuario o la selección de la cuenta entre cuentas con sesiones activas.
En la segunda etapa del flujo de autorización, controlará la respuesta de autenticación llamando a la función auth.complete_log_in
dentro del controlador de redirect_uri, como se muestra:
@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"))
La función complete_log_in()
toma el diccionario de auth_response
entrante como parámetros de consulta. Si se ejecuta correctamente, la función redirige al usuario a la ruta "index" mediante redirect(url_for("index"))
. Esto significa que el usuario ha iniciado sesión correctamente en su información está disponible como un diccionario que contiene notificaciones de un token de identificador ya validado.
Si el resultado contiene un error determinado por la condición if "error" in result:
, represente la "auth_error.html"
plantilla al usuario.
Cerrar la sesión de los usuarios
Para cerrar la sesión de los usuarios de la aplicación de Flask, invoque el método auth.log_out()
de la siguiente manera:
@app.route("/logout")
def logout():
return redirect(auth.log_out(url_for("index", _external=True)))
Cuando un usuario navega a la ruta de dirección URL de /logout
en la aplicación, Flask invoca la función de cierre de sesión que las cierra de sesión de la aplicación actual. También se especifica la página a la que deben redirigirse los usuarios después de cerrar sesión. En el fragmento de código, redirigemos a los usuarios a la página principal de la aplicación mediante url_for("index", _external=True).
Definición de un punto de entrada para la aplicación web
Después de implementar la lógica de inicio de sesión y cierre de sesión, agregue un punto de entrada a la página principal de la aplicación mediante la creación de la función index()
como se indica a continuación:
@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__)
La función index()
se invoca cuando un usuario navega a la dirección URL raíz de la aplicación("/"). Controla las comprobaciones de configuración y valida la autenticación del usuario antes de representar la página principal de la aplicación. Comprueba si faltan el identificador de cliente y el secreto de cliente en la configuración y, si faltan o ambos valores, Flask representa la plantilla de "config_error.html"
.
La función también llama a auth.get_user()
para comprobar si el usuario está autenticado o no. Si el usuario no está autenticado, los redirige a la ruta "login"
. Si se autentica, Flask representa la plantilla "index.html" y pasa el objeto de usuario (recuperado de auth.get_user()
) para su representación.