Cómo realizar la autenticación de usuario con Flask-Login — CodesCode

Aprende sobre las características que ofrece Flask-Login y cómo utilizarlas para crear una función de inicio de sesión segura para tu aplicación web de Python.

En este artículo, analizaremos las diversas características que ofrece Flask-Login y cómo usarlas para crear una funcionalidad de inicio de sesión segura para tu aplicación web. Al final de este artículo, tendrás una buena comprensión de cómo usar Flask-Login para implementar autenticación segura de usuarios en tus aplicaciones Flask.

La autenticación es una parte importante de cualquier aplicación web que permite a los usuarios acceder a datos o recursos, ya que asegura que solo las personas adecuadas tengan acceso a información sensible. Esto también se puede lograr en Flask utilizando Flask-Login.

Flask-Login es una extensión en Flask con funciones que manejan el inicio de sesión y cierre de sesión de los usuarios, y realiza un seguimiento de los usuarios actuales en toda la aplicación. Esto facilita la implementación de autenticación y autorización en tus aplicaciones Flask.

¿Por qué usar Flask-Login?

Flask-Login cuenta con varias características y funciones que facilitan la autenticación sin problemas en aplicaciones Flask. Aquí tienes algunos de los beneficios de usar Flask-Login:

  • Gestión de sesiones de usuario. Flask-Login maneja la creación y destrucción de sesiones de usuario. También puede almacenar el ID del usuario actual en la sesión para que puedas verificar fácilmente si un usuario ha iniciado sesión.

  • Funcionalidad de inicio de sesión y cierre de sesión. Flask-Login proporciona funciones integradas de inicio y cierre de sesión. Estas funciones se encargan de todos los procesos importantes, como la creación y destrucción de sesiones y la redirección del usuario a la página adecuada.

  • Callback de carga de usuario. Flask-Login te permite definir un callback de carga de usuario. Este callback se utiliza para cargar el objeto de usuario para la sesión actual. Esto es útil si estás utilizando una base de datos para almacenar información de usuario.

  • Autenticación y autorización. Flask-Login facilita la implementación de autenticación y autorización en tus aplicaciones. Puedes usar Flask-Login para proteger páginas o rutas específicas y otorgar diferentes niveles de acceso a los usuarios en tu aplicación.

Requisitos previos

Para seguir este artículo, necesitas lo siguiente:

  • Conocimiento de Python y la sintaxis de Flask
  • Conocimientos básicos de HTML y CSS
  • Python versión 3 y Flask instalados

Obviamente, también necesitarás acceso a un navegador web.

Primeros pasos

Para aprovechar al máximo el módulo de inicio de sesión de Flask, necesitamos tener instalado Flask-Login y otras dependencias necesarias. Estas bibliotecas proporcionan las funciones y herramientas necesarias para mejorar la funcionalidad de tu aplicación. Para instalarlas, abre tu línea de comandos o terminal y ejecuta el siguiente comando pip:

pip install flask-login flask_sqlalchemy flask_bcrypt

Aquí tienes una descripción de para qué se utiliza cada una de estas bibliotecas:

  • Flask-SQLAlchemy: integra SQLAlchemy con Flask para operaciones de base de datos
  • Flask-Bcrypt: agrega hashing bcrypt para seguridad de contraseñas en Flask

Una vez completada la instalación, Flask login se descargará automáticamente en el directorio que utilizaste.

Nota: al momento de la escritura, hay un pequeño problema en la resolución de las dependencias en la última versión de Flask y Werkzeug. Para resolver esto, debes forzar la instalación de la versión 2.3.0 de Werkzeug, ya que es la única versión conocida que funciona correctamente en este momento.

Una vez instaladas tus dependencias, deberás inicializarlas con tu aplicación Flask:

from flask_sqlalchemy import SQLAlchemy
from flask_login import UserMixin, LoginManager, login_user, logout_user, login_required
from flask_bcrypt import Bcrypt
from flask_login import LoginManager

app = Flask(__name__)

login_manager = LoginManager()
login_manager.init_app(app)

En el fragmento de código anterior, también hemos inicializado el objeto LoginManager en nuestra aplicación. LoginManager es una extensión de Flask-Login que se utiliza para configurar las configuraciones necesarias para manejar las sesiones de usuario.

Creando un modelo de usuario

Un modelo es una representación de la estructura de datos que desea utilizar en su aplicación. Define cómo se organiza, almacena y manipula los datos dentro del sistema. Los modelos generalmente se usan con una base de datos que sigue la estructura definida previamente. Para nuestra aplicación, tenemos los siguientes datos:

  • un ID único
  • un nombre de usuario
  • una contraseña (encriptada)
class User(UserMixin):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), unique=True)
    password_hash = db.Column(db.String(128))

    def __repr__(self):
        return f'<User {self.username}>'

También puede agregar propiedades adicionales a su modelo de usuario, como una dirección de correo electrónico o una foto de perfil, dependiendo del alcance de su proyecto.

Creando una base de datos

Una vez que haya definido su modelo de usuario, debe crear una base de datos que almacenará la estructura de datos que creamos en el modelo anterior.

Para este artículo, estaremos utilizando una base de datos SQLite. Esto se debe a que SQLite es un motor de base de datos liviano y sin servidor. Esto facilita su configuración y uso, ya que no requiere una instalación aparte. También es una buena opción para aplicaciones pequeñas a medianas.

Aquí hay una descripción de los pasos para usar una base de datos SQLite en nuestra aplicación:

  1. Para utilizar la base de datos SQLite, debe establecer un URI en la configuración de su aplicación Flask. Esto generalmente se hace en la parte superior, junto con otras configuraciones. Aquí hay un fragmento que puede usar:

    app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///site.db' # Usando SQLite como la base de datos

    En este fragmento, el ///... indica la ruta relativa a su archivo – site.db – que es el nombre que usamos para nuestro archivo de base de datos SQLite. Este nombre se puede cambiar a cualquier cosa que prefiera.

  2. A continuación, debe inicializar el ORM Flask-SQLAlchemy usando este fragmento:

    db = SQLAlchemy(app)

    SQLAlchemy es un mapeador objeto-relacional que proporciona un conjunto de herramientas para trabajar con bases de datos utilizando Python. La línea db = SQLAlchemy(app) crea una instancia de la clase SQLAlchemy y la vincula a su aplicación Flask (app).

  3. Para crear esta base de datos, debemos inicializar la base de datos usando el método create_all:

    if __name__ == '__main__':
        db.create_all()
        app.run(debug=True)

    Este código se coloca típicamente al final de su script de Python o en un script separado dedicado a inicializar la base de datos. Una vez que ejecute su script, se creará el archivo de base de datos con las tablas correspondientes basadas en los modelos que definimos anteriormente.

    En este caso, el código creará un archivo site.db con una tabla User si aún no existe. El archivo site.db generalmente se encuentra en una carpeta llamada /instance/.

    La estructura de archivos de nuestra aplicación

A continuación, debemos crear un user_loader que tome un ID de usuario y devuelva el objeto User correspondiente. Aquí hay un ejemplo:

@login_manager.user_loader
def load_user(user_id):
    return User.query.get(user_id)

Encriptación de contraseñas

La encriptación de contraseñas es una medida de seguridad que almacena la representación criptográfica de la contraseña del usuario antes de almacenarla en una base de datos. De esta manera, se vuelve más difícil obtener la contraseña real incluso cuando la seguridad de la aplicación se ha visto comprometida.

Por lo general, la contraseña se encripta primero en el proceso de registro y se almacena en una base de datos. Luego, cada vez que un usuario inicia sesión, su contraseña se vuelve a encriptar y se compara con la contraseña encriptada almacenada en la base de datos. Si las dos contraseñas coinciden, el usuario está autenticado y se le da acceso a la aplicación.

Cómo hashear y verificar contraseñas usando Flask-Bcrypt

Flask tiene una extensión llamada Flask-Bcrypt que ayuda a lograr esta funcionalidad. Tiene dos funciones principales: generate_password_hash() y check_password_hash().

La función generate_password_hash() toma la contraseña del usuario como argumento y devuelve una contraseña hasheada. Esto se usa generalmente en la lógica de registro.

La función check_password_hash() toma una contraseña y una contraseña hasheada como argumentos y devuelve true si las dos contraseñas coinciden, o false si no coinciden. Esto se llama antes de otorgar acceso a la vista de inicio de sesión.

Creando una vista de registro

Vistas son una parte del framework Flask que se utiliza para generar HTML, JSON u otros datos que se envían al navegador del usuario. En este fragmento de código, vamos a crear una vista que reciba la entrada del usuario y agregue los detalles a la base de datos:

@app.route('/register', methods=['GET', 'POST'])
def register():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        hashed_password = bcrypt.generate_password_hash(password).decode('utf-8')
        new_user = User(username=username, password=hashed_password)
        db.session.add(new_user)
        db.session.commit()
        return redirect(url_for('welcome'))
    return render_template('registeration.html')

Desglose del código:

  • En la primera línea, definimos una ruta para la URL /login. Esta ruta acepta tanto solicitudes GET como POST. La función login(), asociada con la ruta, se ejecutará cuando se realice una solicitud.

  • Luego, confirmamos si el método de la solicitud es POST:

    if request.method == 'POST':

    Una vez confirmado, la función obtiene los valores ingresados por el usuario en el formulario de inicio de sesión:

    username = request.form['username']
    password = request.form['password']
  • Luego consulta la base de datos en busca de un usuario con el nombre de usuario proporcionado. Si se encuentra un usuario con el nombre de usuario proporcionado y la contraseña coincide, se ejecutará el código dentro de este bloque.

Creando una vista de inicio de sesión

En la vista de inicio de sesión, creamos una lógica que acepta la entrada desde una página y luego verifica si la entrada coincide con alguna fila en la base de datos:

@app.route('/login', methods=['GET', 'POST'])
def login():
    if request.method == 'POST':
        username = request.form['username']
        password = request.form['password']
        user = User.query.filter_by(username=username).first()
        if user and bcrypt.check_password_hash(user.password, password):
            login_user(user)
            return redirect(url_for('welcome'))
    return render_template('login.html')

Desglose del código:

  • En la primera línea – @app.route('/login', methods=['GET', 'POST']): – estamos utilizando un decorador que define una ruta para la URL /login. La ruta acepta tanto solicitudes GET como POST. La función asociada, login(), se ejecutará cuando se realice una solicitud a esta ruta.

  • La función login() comienza comprobando si el método de la solicitud es POST:

    if request.method == 'POST':

    Una vez confirmado que es una solicitud POST, recupera los valores ingresados por el usuario en el formulario de inicio de sesión:

    username = request.form['username']
    password = request.form['password']
  • Luego consulta la base de datos en busca de un usuario con el nombre de usuario proporcionado:

    user = User.query.filter_by(username=username).first()
    if user and bcrypt.check_password_hash(user.password, password):
  • Si tanto el nombre de usuario como la contraseña son validados, se le otorga acceso al usuario mediante las funciones login_user y redirect de Flask-Login:

    login_user(user)
    redirect(url_for('welcome'))
  • Sin embargo, si el método de la request no es POST o los detalles son incorrectos, se renderiza la plantilla login.html:

    return render_template('login.html')

    En resumen, verifica si las credenciales ingresadas son válidas, inicia sesión al usuario y lo redirige a la página de bienvenida si tiene éxito. Si el inicio de sesión no tiene éxito o es una solicitud GET, se renderiza la plantilla de inicio de sesión para que el usuario ingrese sus credenciales.

Creando la lógica de cierre de sesión utilizando una vista protegida

En la mayoría de las aplicaciones, algunas páginas son inaccesibles si el usuario no ha iniciado sesión. Esto incluye páginas como el historial de transacciones, borradores y páginas de cierre de sesión. Flask-Login proporciona una forma conveniente de proteger estas páginas/rutas y restringir el acceso a usuarios autenticados utilizando el decorador login_required. Aquí tienes una explicación de cómo funciona.

Para utilizar esta funcionalidad, debes importar el decorador login_required de Flask-Login:

from flask_login import login_required

A continuación, debes agregar el decorador login_required a cualquier ruta que desees proteger. Por ejemplo, vamos a crear una página de cierre de sesión que solo se puede acceder cuando el usuario ha iniciado sesión:

@app.route('/logout')  @login_required  def  logout():    logout_user()    return redirect(url_for('login'))

Aquí tienes una explicación de cómo funciona:

  • Al igual que en la vista de inicio de sesión, @app.route('/logout') define una ruta para la URL /logout.

  • A continuación, agregamos un decorador login_required que asegura que el usuario debe haber iniciado sesión para acceder a la ruta logout. Si un usuario no ha iniciado sesión e intenta acceder a esta ruta, será redirigido a la página de inicio de sesión.

  • Dentro de la función logout, se llama a logout_user(). Esta función es proporcionada por Flask-Login y se utiliza para cerrar la sesión del usuario actual.

  • Después de cerrar la sesión del usuario, la función lo redirige a la ruta login utilizando redirect(url_for('login')).

Entonces, cuando un usuario accede a la ruta /logout, Flask-Login se asegura de que haya iniciado sesión (@login_required), lo cierra la sesión y lo redirige a la página de inicio de sesión. Esto ayuda a manejar el cierre de sesión de manera segura en tu aplicación Flask. El decorador login_required se aplica a la ruta /protected, lo que indica que solo los usuarios autenticados pueden acceder. Y si un usuario intenta acceder a una página protegida sin haber iniciado sesión, Flask-Login lo redirigirá a la página de inicio de sesión.

Agregando plantillas

Las plantillas en Flask te permiten utilizar páginas HTML para definir cómo se verá tu sitio. Para implementar completamente la lógica en nuestro archivo app.py, vamos a crear las siguientes páginas HTML:

Estructura de archivos de nuestra aplicación

A continuación, se muestra una animación que muestra cómo las plantillas representan las diferentes páginas de nuestro sitio:

https://player.vimeo.com/video/884411943

Puedes ver el código completo de este tutorial y obtener más información sobre su implementación en el repositorio de GitHub de este artículo.

Cómo Flask-Login maneja las sesiones de usuario con cookies de sesión de usuario

Una sesión de usuario es un sistema utilizado para realizar un seguimiento y actualizar la información del usuario mientras este ha iniciado sesión. Flask-Login administra estas sesiones almacenando una cookie de sesión en el navegador del usuario. La cookie de sesión es un pequeño fragmento de datos que contiene un identificador único para la sesión del usuario.

Cuando un usuario inicia sesión en un sitio web utilizando Flask-Login, el servidor genera una cookie de sesión y la envía al navegador del usuario. El navegador almacena la cookie de sesión y la incluye en todas las peticiones al servidor. El servidor utiliza la cookie de sesión para identificar al usuario y su estado de sesión.

Por ejemplo, si el usuario ha iniciado sesión y visita una página protegida por Flask-Login, Flask-Login verifica la cookie de sesión para ver si el usuario está autenticado. Si el usuario está autenticado, Flask-Login cargará la información del perfil del usuario desde la base de datos y la pondrá a disposición de la vista. Si el usuario no está autenticado, Flask-Login redirigirá al usuario a la página de inicio de sesión.

Cuando el usuario cierra sesión en el sitio web, el servidor elimina la cookie de sesión del navegador del usuario, lo que termina la sesión del usuario.

Conclusión

Flask ofrece una variedad de funciones que abordan diferentes aspectos de la autenticación, desde la gestión de la sesión del usuario hasta la autorización. Al utilizar estas funciones, puedes implementar un sistema de autenticación robusto y seguro adaptado a las necesidades específicas de tu aplicación.

Comparte este artículo


Leave a Reply

Your email address will not be published. Required fields are marked *