Autenticación con JWT en Flask

Publicado por Andrea Navarro en

En esté artículo veremos como implementar autenticación a través de JWT en nuestra aplicación Flask utilizando la extensión Flask-JWT-Extended

Flask-JWT-Extended es una extensión para Flask que agrega soporte para el uso de JSON Web Tokens (JWT) para autenticación permitiendo la protección de rutas. Entre sus características se encuentra la posibilidad de agregar información a los tokens, cargar valores correspondientes a los usuarios de manera automática, la posibilidad de refrescar y revocar tokens y el almacenamiento de tokens en cookies.

Instalación

Es posible instalar la extensión utilizando el manejador de paquetes pip.

pip install flask-jwt-extended

Para el uso de algoritmos de cifrado asimétrico es necesario instalar requerimientos extras

pip install flask-jwt-extended[asymmetric_crypto]

Configuración

Para utilizar Flask-JWT-Extended es necesario cargar el valor de JWT_SECRET_KEY en la configuración de la aplicación. Este valor debe ser seguro ya que será usado para firmar los JWT que se generen en la aplicación.

Luego debe inicializarse la clase JWTManager que será encargada de manejar los tokens pasándole por argumento la variable de la aplicación Flask.

app.config["JWT_SECRET_KEY"] = "ejemplo-clave-secreta"
jwt = JWTManager(app)

Crear JWT

Para crear un JWT se utiliza la función create_access_token. Esta función tomará como argumento identity que deberá contener el valor utilizado para identificar inequívocamente al usuario que poseerá el token. Este valor puede ser un ID correspondiente a la clave de una base de datos o cualquier otro valor único como nombre de usuario o e-mail.

token = create_access_token(identity=ID_usuario)

Este proceso de creación de token, dependiendo de la naturaleza de la aplicación, puede estar procedida por una verificación de autenticación usuario/contraseña, autenticación de doble factor o autenticación externa.

Para devolver el token creado normalmente se convertirá en formato JSON con la función jsonify de manera que puedan ser enviados en un formato de texto plano.

return jsonify(token=token)

Proteger rutas

Dentro de la aplicación Flask creada es posible proteger ciertas rutas de manera que solo puedan ser accedidas si las solicitudes realizadas llevan consigo un token JWT válido. Para proteger estas rutas se utiliza el decorador jwt_required.

@app.route("/ejemplo-ruta")
@jwt_required()
def ejemploRuta():
  # Implementación de la función

En este ejemplo cualquier solicitud que no contenga un token o este no sea válido no podrá acceder a la función. Es posible permitir el acceso a una ruta independientemente si un token es enviado utilizando la opción optional.

@app.route("/ejemplo-ruta")
@jwt_required(optional=True)
def ejemploRuta():
          # Implementación de la función

Colocar el requerimiento de JWT como opcional permite que el token sea procesado y sea posible modificar el comportamiento de la aplicación dependiendo de la identidad del usuario u otros valores almacenados dentro del token.

Carga de usuario

Flask-JWT-Extended provee dos funciones que permiten manejar los datos asociados a un usuario de manera que sea posible acceder estos datos de manera automática a partir de un JWT enviado y obtener la identidad que es requerida para la creación de un JWT a partir de el objeto del usuario.

La función user_identity_loader convertirá el objeto de usuario pasado como argumento en la identidad utilizada para crear el JWT y lo devolverá como texto plano. En el siguiente ejemplo la función tomará el atributo id del objeto usuario como identidad.

@jwt.user_identity_loader
def user_identity_lookup(usuario):
    return usuario.id

Por otro lado, la función user_lookup_loader cargará automáticamente el usuario cada vez que un JWT sea enviado en la solicitud. El usuario correspondiente podrá ser accedido en las rutas protegidas a través del atributo current_user.

@jwt.user_lookup_loader
def user_lookup_callback(_jwt_header, jwt_data):
    id = jwt_data["ID"]
    # Obtener usuario a partir de ID
    # Devolver objeto usuario

Almacenamiento de claims

Es posible ingresar información extra dentro del token utilizando el argumento additional_claims en la creación del tokens pasando los valores en forma de diccionario.

claims = {"nombre": "Pedro", "edad": 39}
token = create_access_token(identity=ID_usuario, additional_claims= claims )

Si se quiere que los claims sean cargados de la misma forma cada vez que se crea un token se puede definir el decorador additional_claims_loader. Este devolverá los claims en forma de diccionario para ser agregados en el token.

@jwt.additional_claims_loader
def add_claims_to_access_token(identity):
     return = {
        "nombre": "Pedro",
         "edad": 39
     }

Para acceder a las claims de un JWT una vez que este ha sido leído se utiliza la función get_jwt.

 claims = get_jwt()
 print(claims["nombre"])

En este artículo hemos visto como utilizar la extensión Flask-JWT-Extended para la creación y manejo de JWT como método de protección de rutas en nuestra aplicación Flask. Espero que les sea de utilidad.


¿Preguntas? ¿Comentarios?

Si tenés dudas, o querés dejarnos tus comentarios y consultas, sumate al grupo de Telegram de la comunidad JuncoTIC!
¡Te esperamos!

Categorías: Programación

Andrea Navarro

- Ingeniera en Informática - Docente universitaria - Investigadora