Autenticación con JWT en Flask
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.