Les jetons Web JSON sont faciles à utiliser et à déboguer, mais ils offrent également une amélioration impressionnante de la sécurité.
L'authentification brisée continue d'être une vulnérabilité persistante dans les applications Web modernes - elle se classe toujours parmi les 10 principaux risques de sécurité des API de l'OWASP.
Les effets de cette vulnérabilité peuvent être graves. Ils peuvent accorder un accès non autorisé à des données sensibles et compromettre l'intégrité du système. Pour garantir efficacement un accès sécurisé aux applications et à leurs ressources, il est essentiel que vous utilisiez des mécanismes d'authentification robustes.
Découvrez comment vous pouvez implémenter l'authentification des utilisateurs dans Flask à l'aide de JSON Web Tokens (JWT), une méthode populaire et efficace basée sur des jetons.
Authentification basée sur des jetons à l'aide de jetons Web JSON
L'authentification basée sur les jetons utilise une chaîne de caractères cryptée pour valider et autoriser l'accès à un système ou à une ressource. Vous pouvez implémenter ce type d'authentification à l'aide de différentes méthodes, notamment les jetons de session, les clés API et les jetons Web JSON.
Les JWT, en particulier, offrent une approche sécurisée et compacte pour la transmission des informations d'identification des utilisateurs requises entre les applications côté client et les serveurs.
Un JWT se compose de trois composants principaux: l'en-tête, la charge utile et la signature. L'en-tête contient des métadonnées sur le jeton, y compris l'algorithme de hachage utilisé pour coder le jeton.
La charge utile contient les informations d'identification réelles de l'utilisateur, telles que l'ID utilisateur et les autorisations. Enfin, la signature assure la validité du jeton en vérifiant son contenu à l'aide d'une clé secrète.
À l'aide de JWT, vous pouvez authentifier les utilisateurs et stocker les données de session dans le jeton lui-même.
Configurer un projet Flask et une base de données MongoDB
Pour commencer, créez un nouveau répertoire de projet à l'aide d'un terminal :
projet de flacon mkdir
cd flacon-projet
Ensuite, installez environnement virtuel, pour créer un environnement de développement virtuel local pour votre projet Flask.
virtualenv venv
Enfin, activez l'environnement virtuel.
# Unix ou MacOS:
source venv/bin/activer
# Les fenêtres:
.\venv\Scripts\activate
Vous pouvez trouver le code de ce projet dans ce Référentiel GitHub.
Installer les packages requis
Dans le répertoire racine de votre dossier de projet, créez un nouveau exigences.txt fichier et ajoutez ces dépendances pour le projet :
ballon
pyjwt
python-dotenv
pymongo
bcrypt
Enfin, exécutez la commande ci-dessous pour installer les packages. Assurez-vous que vous avez pépin (gestionnaire de packages) installé; sinon, installez-le sur votre système Windows, Mac ou Linux.
pip install -r exigences.txt
Créer une base de données MongoDB
Allez-y et créez une base de données MongoDB. Tu peux configurer une base de données MongoDB locale, alternativement, créer un cluster sur MongoDB Atlas, un service MongoDB basé sur le cloud.
Une fois que vous avez créé la base de données, copiez l'URI de connexion, créez un .env fichier dans le répertoire racine de votre projet, et ajoutez-le comme suit :
MONGO_URI=""
Enfin, configurez la connexion à la base de données depuis votre application Flask. Créer un nouveau utils/db.py fichier dans le répertoire racine de votre projet, avec ce code :
depuis pymongo importer MongoClient
définitivementconnect_to_mongodb(mongo_uri):
client = MongoClient (mongo_uri)
db = client.get_database("utilisateurs")
retour db
Cette fonction établit une connexion à la base de données MongoDB à l'aide de l'URI de connexion fourni. Il crée alors un nouveau utilisateurs collection si elle n'existe pas, et renvoie l'instance de base de données correspondante.
Créer le serveur Web Flask
Avec la base de données configurée, continuez et créez un app.py dans le répertoire racine du dossier du projet et ajoutez le code suivant pour créer une instance de l'application Flask.
depuis ballon importer Ballon
depuis routes.user_auth importer registre_routes
depuis utils.db importer connect_to_mongodb
importer os
depuis dotenv importer load_dotenvapp = flacon (__nom__)
load_dotenv()mongo_uri = os.getenv('MONGO_URI')
db = connect_to_mongodb (mongo_uri)register_routes (application, base de données)
si __nom__ == '__principal__':
app.run (débogage=Vrai)
Créer les points de terminaison de l'API d'authentification
Pour implémenter l'authentification des utilisateurs dans votre application Flask, il est essentiel de définir les points de terminaison d'API nécessaires qui gèrent les opérations liées à l'authentification.
Cependant, commencez par définir le modèle pour les données des utilisateurs. Pour ce faire, créez un nouveau modèle/user_model.py fichier dans le répertoire racine et ajoutez le code suivant.
depuis pymongo.collection importer Collection
depuis bson.objectid importer ID d'objetclasseUtilisateur:
définitivement__init__(self, collection: Collection, nom d'utilisateur: str, mot de passe: str):
self.collection = collection
self.username = nom d'utilisateur
self.password = mot de passe
définitivementsauvegarder(soi):
données_utilisateur = {
'nom d'utilisateur': self.username,
'mot de passe': self.password
}
result = self.collection.insert_one (user_data)
retour str (result.insert_id)@méthodestatique
définitivementfind_by_id(collection: Collection, user_id: str):
retour collection.find_one({'_identifiant': ObjectId (identifiant_utilisateur)})
@méthodestatique
définitivementfind_by_username(collection: Collection, nom d'utilisateur: str):
retour collection.find_one({'nom d'utilisateur': nom d'utilisateur})
Le code ci-dessus spécifie un Utilisateur classe qui sert de modèle de données et définit plusieurs méthodes pour interagir avec une collection MongoDB afin d'effectuer des opérations liées à l'utilisateur.
- Le sauvegarder La méthode enregistre un nouveau document utilisateur avec le nom d'utilisateur et le mot de passe fournis dans la collection MongoDB et renvoie l'ID du document inséré.
- Le find_by_id et find_by_username Les méthodes récupèrent les documents utilisateur de la collection en fonction de l'ID utilisateur ou du nom d'utilisateur fourni, respectivement.
Définir les routes d'authentification
- Commençons par définir la route d'enregistrement. Cette route ajoutera de nouvelles données utilisateur à la collection d'utilisateurs MongoDB. Dans le répertoire racine, créez un nouveau routes/user_auth.py fichier et le code suivant.
importer jwt
depuis outils de fonction importer enveloppe
depuis ballon importer jsonify, demande, make_response
depuis modèles.user_model importer Utilisateur
importer bcrypt
importer osdéfinitivementregistre_routes(application, base de données):
collection = db.users
app.config['CLEF SECRÈTE'] = os.urandom(24)@app.route('/api/register', methodes=['POST'])
définitivementenregistrer():
nom d'utilisateur = request.json.get('nom d'utilisateur')
mot de passe = request.json.get('mot de passe')
existing_user = User.find_by_username (collection, nom d'utilisateur)
si utilisateur existant:
retour jsonifier({'message': 'Ce nom d'utilisateur existe déjà!'})
hashed_password = bcrypt.hashpw (password.encode('utf-8'), bcrypt.gensalt())
new_user = Utilisateur (collection, nom d'utilisateur, hashed_password.decode('utf-8'))
user_id = new_user.save()retour jsonifier({'message': 'L'utilisateur s'est enregistré avec succès !', 'ID de l'utilisateur': ID de l'utilisateur})
- Implémentez la fonctionnalité de connexion pour gérer le processus d'authentification et vérifier les informations d'identification de l'utilisateur. Sous la route d'enregistrement, ajoutez le code suivant.
Le point de terminaison de connexion fait deux choses: il vérifie les informations d'identification de l'utilisateur fournies et, une fois l'authentification réussie, il génère un JWT unique pour cet utilisateur. Il définit ce jeton en tant que cookie dans la réponse, ainsi qu'une charge utile JSON indiquant une connexion réussie. Si les informations d'identification ne sont pas valides, il renverra une réponse JSON pour l'indiquer.@app.route('/api/login', methodes=['POST'])
définitivementconnexion():
nom d'utilisateur = request.json.get('nom d'utilisateur')
mot de passe = request.json.get('mot de passe')
user = User.find_by_username (collection, nom d'utilisateur)
si utilisateur:
si bcrypt.checkpw (mot de passe.encode('utf-8'), utilisateur['mot de passe'].encoder('utf-8')):
jeton = jwt.encode({'ID de l'utilisateur': chaîne (utilisateur['_identifiant'])}, app.config['CLEF SECRÈTE'], algorithme='HS256')
réponse = make_response (jsonify({'message': 'Connexion réussie!'}))
réponse.set_cookie('jeton', jeton)
retour réponseretour jsonifier({'message': 'Nom d'utilisateur ou mot de passe invalide'})
- Définissez une fonction de décoration qui vérifie les jetons Web JSON (JWT) transmis avec les demandes d'API ultérieures. Ajoutez le code ci-dessous dans le registre_routes bloc de code de fonction.
Cette fonction de décorateur garantit la présence d'un jeton JWT valide dans les requêtes API ultérieures. Il vérifie si le jeton est manquant, expiré ou valide, et renvoie une réponse JSON appropriée si c'est le cas.définitivementtoken_required(F):
@wraps (f)
définitivementdécoré(*args, **kwargs):
jeton = request.cookies.get('jeton')sipas jeton:
retour jsonifier({'message': 'Jeton manquant !'}), 401essayer:
data = jwt.decode (jeton, app.config['CLEF SECRÈTE'], algorithmes=['HS256'])
current_user = User.find_by_id (collection, données['ID de l'utilisateur'])
sauf jwt. Erreur de signature expirée :
retour jsonifier({'message': 'Le jeton a expiré !'}), 401
sauf jwt. Erreur de jeton invalide :
retour jsonifier({'message': 'Jeton invalide!'}), 401retour f (utilisateur_actuel, *args, **kwargs)
retour décoré
- Enfin, créez un itinéraire protégé.
@app.route('/api/users', methodes=['GET'])
@token_required
définitivementget_users(utilisateur actuel):
utilisateurs = liste (collection.find({}, {'_identifiant': 0}))
retour jsonify (utilisateurs)
Ce point de terminaison gère la logique de récupération des données utilisateur à partir de la base de données, mais il nécessite que le client qui envoie les demandes inclue un jeton valide pour accéder aux données.
Enfin, exécutez la commande ci-dessous pour lancer le serveur de développement.
course de ballon
Pour tester l'enregistrement, la connexion et le point de terminaison des utilisateurs protégés, vous pouvez utiliser Postman ou tout autre client API. Envoyez vos demandes à http://localhost: 5000/api/et observez les réponses pour vérifier la fonctionnalité de ces points de terminaison d'API.
L'authentification par jeton est-elle une mesure de sécurité infaillible?
Les jetons Web JSON offrent un moyen robuste et efficace d'authentifier les utilisateurs pour votre application Web. Cependant, il est important de comprendre que l'authentification par jeton n'est pas infaillible; ce n'est qu'une pièce d'un puzzle de sécurité plus vaste.
Combinez l'authentification par jeton avec d'autres bonnes pratiques de sécurité. N'oubliez pas de surveiller en permanence et d'adopter des pratiques de sécurité cohérentes; vous améliorerez considérablement la sécurité globale de vos applications Flask.