Los tokens web JSON son fáciles de usar y depurar, pero también ofrecen un aumento de seguridad impresionante.
La autenticación rota sigue siendo una vulnerabilidad persistente en las aplicaciones web modernas; todavía ocupa un lugar destacado entre los 10 principales riesgos de seguridad de API de OWASP.
Los efectos de esta vulnerabilidad pueden ser graves. Pueden otorgar acceso no autorizado a datos confidenciales y comprometer la integridad del sistema. Para garantizar de manera efectiva el acceso seguro a las aplicaciones y sus recursos, es fundamental que utilice mecanismos de autenticación sólidos.
Descubra cómo puede implementar la autenticación de usuarios en Flask mediante JSON Web Tokens (JWT), un método popular y eficaz basado en tokens.
Autenticación basada en token mediante tokens web JSON
La autenticación basada en tokens utiliza una cadena de caracteres cifrada para validar y autorizar el acceso a un sistema o recurso. Puede implementar este tipo de autenticación mediante varios métodos, incluidos tokens de sesión, claves de API y tokens web JSON.
Los JWT, en particular, ofrecen un enfoque seguro y compacto para transmitir las credenciales de los usuarios requeridos entre las aplicaciones del lado del cliente y los servidores.
Un JWT consta de tres componentes principales: el encabezado, la carga útil y la firma. El encabezado contiene metadatos sobre el token, incluido el algoritmo hash utilizado para codificar el token.
La carga útil contiene las credenciales reales del usuario, como el ID de usuario y los permisos. Por último, la firma asegura la validez del token al verificar su contenido mediante una clave secreta.
Con JWT, puede autenticar usuarios y almacenar datos de sesión, todo dentro del token mismo.
Configurar un proyecto Flask y una base de datos MongoDB
Para comenzar, cree un nuevo directorio de proyecto usando una terminal:
proyecto matraz mkdir
proyecto de matraz de cd
A continuación, instale entorno virtual, para crear un entorno de desarrollo virtual local para su proyecto Flask.
entorno virtual venv
Finalmente, active el entorno virtual.
# Unix o MacOS:
fuente venv/bin/activar
# Ventanas:
.\venv\Scripts\activar
Puedes encontrar el código de este proyecto en este repositorio GitHub.
Instale los paquetes necesarios
En el directorio raíz de la carpeta de su proyecto, cree un nuevo requisitos.txt y agregue estas dependencias para el proyecto:
matraz
pyjwt
python-dotenv
pymongo
cripta
Por último, ejecute el siguiente comando para instalar los paquetes. Asegúrate de tener pepita (gestor de paquetes) instalado; si no, instálelo en su sistema Windows, Mac o Linux.
pip install -r requisitos.txt
Crear una base de datos MongoDB
Continúe y cree una base de datos MongoDB. Puede configurar una base de datos MongoDB local, alternativamente, crear un clúster en MongoDB Atlas, un servicio MongoDB basado en la nube.
Una vez que haya creado la base de datos, copie el URI de conexión, cree un .env archivo en el directorio raíz de su proyecto, y agréguelo de la siguiente manera:
MONGO_URI=""
Finalmente, configure la conexión de la base de datos desde su aplicación Flask. Crear un nuevo utils/db.py archivo en el directorio raíz de su proyecto, con este código:
de pymongo importar MongoCliente
definitivamenteconectar_a_mongodb(mongo_uri):
cliente = MongoClient (mongo_uri)
db = cliente.get_database("usuarios")
devolver base de datos
Esta función establece una conexión a la base de datos MongoDB utilizando el URI de conexión proporcionado. A continuación, crea una nueva usuarios colección si no existe, y devuelve la instancia de base de datos correspondiente.
Crear el servidor web Flask
Con la base de datos configurada, continúe y cree una app.py archivo en el directorio raíz de la carpeta del proyecto y agregue el siguiente código para crear una instancia de la aplicación Flask.
de matraz importar Matraz
de rutas.user_auth importar registrar_rutas
de utils.db importar conectar_a_mongodb
importar sistema operativo
de dotenv importar carga_dotenvapp = Frasco (__nombre__)
cargar_dotenv()mongo_uri = os.getenv('MONGO_URI')
db = conectar_a_mongodb (mongo_uri)register_routes (aplicación, base de datos)
si __nombre__ == '__principal__':
aplicación.ejecutar (depurar=Verdadero)
Crear los puntos finales de la API de autenticación
Para implementar la autenticación de usuario en su aplicación Flask, es crucial definir los puntos finales de API necesarios que manejen las operaciones relacionadas con la autenticación.
Sin embargo, primero, defina el modelo para los datos de los usuarios. Para ello, crea una nueva modelo/usuario_modelo.py archivo en el directorio raíz y agregue el siguiente código.
de pymongo.colección importar Recopilación
de bson.objetoid importar ID de objetoclaseUsuario:
definitivamente__en eso__(self, colección: Colección, nombre de usuario: str, contraseña: str):
self.colección = colección
self.nombre de usuario = nombre de usuario
self.contraseña = contraseña
definitivamenteahorrar(ser):
datos_usuario = {
'nombre de usuario': self.nombre de usuario,
'contraseña': self.contraseña
}
resultado = self.colección.insertar_uno (datos_usuario)
devolver str (resultado.inserted_id)@métodoestático
definitivamenteencontrar_por_id(colección: Colección, user_id: str):
devolver colección.find_one({'_identificación': IdObjeto (id_usuario)})
@métodoestático
definitivamentebuscar_por_nombre de usuario(colección: Colección, nombre de usuario: str):
devolver colección.find_one({'nombre de usuario': nombre de usuario})
El código anterior especifica un Usuario clase que sirve como modelo de datos y define varios métodos para interactuar con una colección MongoDB para realizar operaciones relacionadas con el usuario.
- El ahorrar El método guarda un nuevo documento de usuario con el nombre de usuario y la contraseña proporcionados en la colección de MongoDB y devuelve el ID del documento insertado.
- El encontrar_por_id y buscar_por_nombre de usuario Los métodos recuperan documentos de usuario de la colección en función del ID de usuario o el nombre de usuario proporcionados, respectivamente.
Definir las rutas de autenticación
- Comencemos definiendo la ruta de registro. Esta ruta agregará nuevos datos de usuario a la colección de usuarios de MongoDB. En el directorio raíz, cree un nuevo rutas/auth_user.py archivo y el siguiente código.
importar jwt
de herramientas funcionales importar envuelve
de matraz importar jsonify, solicitud, hacer_respuesta
de modelos.user_model importar Usuario
importar cripta
importar sistema operativodefinitivamenteregistrar_rutas(aplicación, base de datos):
colección = db.usuarios
aplicación.config['LLAVE SECRETA'] = os.urandom(24)@app.route('/api/registrar', métodos=['POST'])
definitivamenteregistro():
nombre de usuario = solicitud.json.get('nombre de usuario')
contraseña = solicitud.json.get('contraseña')
usuario_existente = User.find_by_username (colección, nombre de usuario)
si usuario existente:
devolver jsonify({'mensaje': '¡Nombre de usuario ya existe!'})
hash_password = bcrypt.hashpw (contraseña.encode('utf-8'), bcrypt.gensalt())
new_user = Usuario (colección, nombre de usuario, hash_password.decode('utf-8'))
id_usuario = nuevo_usuario.guardar()devolver jsonify({'mensaje': '¡Usuario registrado con éxito!', 'id_usuario': id_usuario})
- Implemente la funcionalidad de inicio de sesión para manejar el proceso de autenticación y verificar las credenciales de usuario. En la ruta de registro, agregue el siguiente código.
El punto final de inicio de sesión hace dos cosas: verifica las credenciales de usuario proporcionadas y, luego de una autenticación exitosa, genera un JWT único para ese usuario. Establece este token como una cookie en la respuesta, junto con una carga JSON que indica un inicio de sesión exitoso. Si las credenciales no son válidas, devolverá una respuesta JSON para indicarlo.@app.route('/api/login', métodos=['POST'])
definitivamenteacceso():
nombre de usuario = solicitud.json.get('nombre de usuario')
contraseña = solicitud.json.get('contraseña')
usuario = User.find_by_username (colección, nombre de usuario)
si usuario:
si bcrypt.checkpw (contraseña.encode('utf-8'), usuario['contraseña'].codificar('utf-8')):
token = jwt.encode({'id_usuario': str (usuario['_identificación'])}, aplicación.config['LLAVE SECRETA'], algoritmo='HS256')
respuesta = make_response (jsonify({'mensaje': '¡Inicio de sesión correcto!'}))
respuesta.set_cookie('simbólico', ficha)
devolver respuestadevolver jsonify({'mensaje': 'Usuario o contraseña invalido'})
- Defina una función de decorador que verifique los tokens web JSON (JWT) pasados junto con las solicitudes de API posteriores. Agregue el código a continuación dentro del registrar_rutas bloque de código de función.
Esta función de decorador garantiza la presencia de un token JWT válido en las solicitudes de API posteriores. Comprueba si falta el token, si está caducado o si es válido y, si es así, devuelve una respuesta JSON adecuada.definitivamentetoken_required(F):
@envolturas (f)
definitivamentedecorado(*args, **kwargs):
token = solicitud.cookies.get('simbólico')sino simbólico:
devolver jsonify({'mensaje': '¡Falta la ficha!'}), 401intentar:
data = jwt.decode (token, app.config['LLAVE SECRETA'], algoritmos=['HS256'])
usuario_actual = Usuario.buscar_por_id (colección, datos['id_usuario'])
excepto jwt. Error de firma caducada:
devolver jsonify({'mensaje': '¡El token ha caducado!'}), 401
excepto jwt. Error de token no válido:
devolver jsonify({'mensaje': '¡Simbolo no valido!'}), 401devolver f (usuario_actual, *argumentos, **kwargs)
devolver decorado
- Finalmente, cree una ruta protegida.
@app.route('/api/usuarios', métodos=['GET'])
@token_required
definitivamenteobtener_usuarios(usuario actual):
usuarios = lista (colección.find({}, {'_identificación': 0}))
devolver jsonify (usuarios)
Este punto final maneja la lógica para recuperar datos de usuario de la base de datos, pero requiere que el cliente envíe solicitudes para incluir un token válido para acceder a los datos.
Finalmente, ejecute el siguiente comando para activar el servidor de desarrollo.
carrera de matraz
Para probar el registro, el inicio de sesión y el punto final de los usuarios protegidos, puede usar Postman o cualquier otro cliente API. Enviar solicitudes a http://localhost: 5000/api/y observe las respuestas para verificar la funcionalidad de estos puntos finales de la API.
¿Es la autenticación de tokens una medida de seguridad infalible?
Los tokens web JSON proporcionan una forma sólida y eficaz de autenticar a los usuarios de su aplicación web. Sin embargo, es importante comprender que la autenticación de token no es infalible; es solo una pieza de un rompecabezas de seguridad más grande.
Combine la autenticación de token con otras mejores prácticas de seguridad. Recuerde monitorear continuamente y adoptar prácticas de seguridad consistentes; mejorará significativamente la seguridad general de sus aplicaciones Flask.