Tangerine-Auth est une bibliothèque Python qui fournit des services publics pour l'authentification des utilisateurs et la gestion sécurisée des clés et des données cryptées. Il utilise BCrypt pour le hachage de mot de passe et JWT pour l'authentification basée sur les jetons.
Remarque: Tangerine-Auth est actuellement en version bêta. Il n'est pas encore recommandé pour l'utilisation de la production. N'hésitez pas à télécharger et à jouer avec ça en attendant! Nous travaillons sur l'ajout de tests et de documentation. Si vous trouvez des bogues ou avez des suggestions, veuillez ouvrir un problème sur GitHub.
Utilisez PIP pour installer le package:
pip install tangerine-authLes étapes générales pour intégrer Yuzu dans votre application sont les suivantes:
def get_user_by_email ( email ):
conn = psycopg2 . connect ( "postgresql://postgres:<your postgres password>@localhost:5432/local_development" )
cur = conn . cursor ()
cur . execute ( "SELECT * FROM tangerine.users WHERE email = %s" , ( email ,))
user = cur . fetchone ()
cur . close ()
conn . close ()
if user :
return { '_id' : user [ 0 ], 'email' : user [ 1 ], 'password' : user [ 2 ]}
else :
return None
def create_user ( user_data ):
conn = psycopg2 . connect ( "postgresql://<your postgres password>@localhost:5432/local_development" )
cur = conn . cursor ()
cur . execute ( "INSERT INTO tangerine.users (email, password) VALUES (%s, %s) RETURNING id" , ( user_data [ 'email' ], user_data [ 'password' ]))
user_id = cur . fetchone ()[ 0 ]
conn . commit ()
cur . close ()
conn . close ()
return { '_id' : user_id , 'email' : user_data [ 'email' ], 'password' : user_data [ 'password' ]}Créez un objet KeyLime et passez-le au constructeur Yuzu. L'objet KeyLime est utilisé pour gérer solidement les clés et les données cryptées. Vous pouvez utiliser l'objet KeyLime pour crypter et déchiffrer les données, et pour stocker et récupérer les clés.
Créez un objet Yuzu et passez-le l'objet KeyLime, la fonction pour trouver un utilisateur dans votre base de données et la fonction de création d'un utilisateur dans votre base de données.
(Facultatif) Yuzu utilise BCrypt pour hacher les mots de passe. Vous pouvez éventuellement transmettre une fonction de hachage personnalisée au constructeur Yuzu. La fonction de hachage personnalisée doit prendre une chaîne de mot de passe comme argument et renvoyer une chaîne de mot de passe hachée.
Une fois l'étape 3 terminée, vous pouvez désormais utiliser l'objet Yuzu pour inscrire un nouvel utilisateur, connecter un utilisateur, connecter un utilisateur et vérifier les jetons d'authentification.
Yuzu a été conçu pour travailler avec Flask ainsi que Tangerine, il y a actuellement deux JWT Middlewares groupés avec Yuzu, un pour Flask et un pour Tangerine. Une fois que vous avez initialisé correctement la classe Yuzu, vous pouvez utiliser le middleware Tangerine en appelant:
app . use ( auth . jwt_middleware ).Le middleware JWT de Flask est toujours expérimental et pourrait être sujet aux problèmes. Il ne sera pas recommandé pour une utilisation en production avant d'avoir été testé de manière plus approfondie. Le middleware JWT fonctionne un peu différent dans Flask, pour l'utiliser avec Flask, vous l'utilisez comme décorateur:
from flask import Flask
from yuzu import Yuzu
app = Flask ( __name__ )
def get_user_by_email ( email ):
# Logic to create user in DB
pass
def create_user ( user_data ):
# Logic to create user in DB
pass
auth = Yuzu ( keychain , get_user_by_email , create_user ) # Fill with your functions
@ app . route ( '/secure_route' )
@ auth . flask_jwt_middleware ( auth )
def secure_route ():
# Your secure code here. This will only run if the JWT is valid.
return "This is a secure route"
if __name__ == "__main__" :
app . run ( debug = True )Remarque: L'AUTH Middleware ajoute les données utilisateur à l'objet CTX. Vous pouvez accéder aux données de l'utilisateur dans votre gestionnaire d'itinéraire en appelant
ctx . auth . user or ctx . get ( "user" )Yuzu est une classe qui fournit des fonctionnalités d'authentification des utilisateurs. Il utilise BCrypt pour le hachage de mot de passe et JWT pour créer et vérifier les jetons d'authentification.
Vous trouverez ci-dessous les méthodes clés de la classe Yuzu:
- `__init__(self, keychain, get_user_by_email, create_user, hash_func: Optional[Callable] = None)` : Initializes the Yuzu object .
- `get_config(self, key_name: str) -> str` : Fetches the configuration value for a given key .
- `authenticate(self, email: str, password: str) -> bool` : Checks if the given email and password are valid .
- `generate_auth_token(self, user_id: str, email: str) -> str` : Generates an authentication token for the given user .
- `verify_auth_token(self, token: str) -> dict` : Verifies if the given authentication token is valid .
- `sign_up(self, user_data: dict) -> dict` : Signs up a new user with the given user data .
- `login(self, email: str, password: str) -> Tuple[str, str]` : Logs in a user with the given email and password .
- `logout(self)` : Logs out the current user .
- `jwt_middleware()` : Tangerine middleware for JWT authentication .
- `flask_jwt_middleware(yuzu_instance)` : Flask middleware for JWT authentication .KeyLime est une classe qui fournit des fonctionnalités pour la gestion des clés en toute sécurité et les données cryptées.
Vous trouverez ci-dessous les méthodes clés de la classe KeyLime:
- `__init__(self, keychain: Dict[str, bytes] = {})` : Initializes the KeyLime object .
- `add_key(self, key_name: str, key: bytes)` : Adds a key to the keychain .
- `remove_key(self, key_name: str)` : Removes a key from the keychain .
- `get_key(self, key_name: str) -> bytes` : Fetches a key from the keychain .
- `encrypt(self, key_name: str, message: str) -> str` : Encrypts a given message using a key from the keychain .
- `decrypt(self, key_name: str, cipher_text: str) -> str` : Decrypts a given cipher text using a key from the keychain .Le concept général est que vous souhaitez écrire deux fonctions, une pour trouver un utilisateur dans votre système de base de données choisi et une pour créer un utilisateur dans votre système de base de données choisi. Ces fonctions devraient prendre un dictionnaire des données utilisateur comme argument et renvoyer un dictionnaire des données utilisateur. Le dictionnaire de données utilisateur doit contenir au moins un champ de messagerie et de mot de passe. Le dictionnaire de données utilisateur peut contenir les autres champs que vous souhaitez stocker dans votre base de données.
Voici un exemple de la façon d'utiliser les classes Yuzu et KeyLime:
from tangerine import Tangerine , Ctx , Router
from pymongo import MongoClient
from tangerine . key_lime import KeyLime
from tangerine . yuzu import Yuzu
import json
import jwt
import hashlib
app = Tangerine ( debug_level = 1 )
client = MongoClient ( 'mongodb://localhost:27017/' )
keychain = KeyLime ({
"SECRET_KEY" : "ILOVECATS" ,
})
def get_user_by_email ( email ):
db = client [ 'mydatabase' ]
users = db [ 'users' ]
query = { 'email' : email }
user = users . find_one ( query )
if user :
user [ '_id' ] = str ( user [ '_id' ]) # Convert ObjectId to string
return user
def create_user ( user_data ):
db = client [ 'mydatabase' ]
users = db [ 'users' ]
result = users . insert_one ( user_data )
if result . inserted_id :
user_data [ '_id' ] = str ( result . inserted_id ) # Convert ObjectId to string
return user_data
auth = Yuzu ( keychain , get_user_by_email , create_user )
# serve static files to any request not starting with /api
app . static ( '^/(?!api).*$' , './public' )
# This is how you define a custom middleware.
def hello_middle ( ctx : Ctx , next ) -> None :
ctx . hello_message = json . dumps ({ "message" : "Hello from middleware!" })
next ()
# ==================== AUTH HANDLERS ====================
def api_hello_world ( ctx : Ctx ) -> None :
ctx . body = ctx . hello_message
ctx . send ( 200 , content_type = 'application/json' )
def signup ( ctx : Ctx ) -> None :
user_data = ctx . request . body
created_user = auth . sign_up ( user_data )
if created_user :
ctx . body = json . dumps ( created_user )
ctx . send ( 201 , content_type = 'application/json' )
else :
ctx . send ( 500 , content_type = 'application/json' )
def login ( ctx : Ctx ) -> None :
user_data = ctx . request . body
email = user_data [ 'email' ]
password = user_data [ 'password' ]
user_id , token = auth . login ( email , password )
print ( ctx . user , "HELLO FROM LOGIN" )
if token :
ctx . body = json . dumps ({ "message" : "Logged in successfully" , "token" : token })
ctx . set_res_header ( "Set-Cookie" , f"auth_token= { token } ; HttpOnly; Path=/" )
ctx . send ( 200 , content_type = 'application/json' )
# Set the token as a cookie or in the response headers
else :
ctx . body = json . dumps ({ "message" : "Invalid credentials" })
ctx . send ( 401 , content_type = 'application/json' )
def logout ( ctx : Ctx ) -> None :
auth . logout ( ctx )
ctx . body = json . dumps ({ "message" : "Logged out successfully" })
ctx . send ( 200 , content_type = 'application/json' )
@ Router . auth_required
def get_protected_content ( ctx : Ctx ) -> None :
ctx . body = json . dumps ({ "message" : "This is protected content. Only authenticated users can see this. I hope you feel special ???." })
ctx . send ( 200 , content_type = 'application/json' )
# ==================== API ROUTES ====================
# if you need to bind more variables to your handler, you can pass in a closure
api_router = Router ( prefix = '/api' )
api_router . post ( '/logout' , logout )
api_router . post ( '/login' , login )
api_router . post ( '/signup' , signup )
api_router . get ( '/hello' , api_hello_world )
# api_router.get('/users', get_and_delete_users)
api_router . get ( '/protected' , get_protected_content )
app . use ( hello_middle )
app . use ( auth . jwt_middleware )
app . use_router ( api_router )
app . start ()Yuzu est conçu pour être flexible, vous permettant de l'adapter aux besoins spécifiques de votre projet. Une façon dont vous pouvez personnaliser son comportement consiste à modifier les fonctions de hachage et de vérification de mot de passe par défaut.
Par défaut, Yuzu utilise la bibliothèque bcrypt pour le hachage et la vérification du mot de passe. Si vous souhaitez utiliser une approche différente, vous pouvez transmettre vos propres fonctions de hachage et de vérification au constructeur de classe Yuzu. Voici un exemple de la façon de le faire:
import hashlib
def my_hash_func ( password : str , salt : str = None ) -> str :
return hashlib . sha256 ( password . encode ()). hexdigest ()
def my_check_password_func ( password : str , hashed_password : str , salt : str = None ) -> bool :
return hashlib . sha256 ( password . encode ()). hexdigest () == hashed_password
auth = Yuzu ( keychain , get_user_by_email , create_user , hash_func = my_hash_func , checkpw_func = my_check_password_func )L'utilisation d'Argon2 pour le hachage Argon2 est un algorithme de hachage de mot de passe moderne et sécurisé qui est recommandé par la concurrence de hachage de mot de passe. Voici un exemple de la façon de l'utiliser avec Yuzu:
from argon2 import PasswordHasher , exceptions
ph = PasswordHasher ( time_cost = 16 , memory_cost = 65536 )
def my_hash_func ( password : str , salt : str = None ) -> str :
return ph . hash ( password )
def my_check_password_func ( password : str , hashed_password : str , salt : str = None ) -> bool :
try :
return ph . verify ( hashed_password , password )
except exceptions . VerifyMismatchError :
return False
auth = Yuzu ( keychain , get_user_by_email , create_user , hash_func = my_hash_func , checkpw_func = my_check_password_func )Ces exemples vous permettent de passer de l'algorithme BCrypt par défaut vers SHA256 ou Argon2. Vous pouvez également modifier ces fonctions pour modifier la difficulté de la fonction de hachage (par exemple, en augmentant le nombre d'itérations ou l'utilisation de la mémoire) selon vos besoins spécifiques.
N'oubliez pas que la modification de ces fonctions peut avoir des implications pour la sécurité de votre application. Vous devez comprendre le fonctionnement de la fonction de hachage choisie et ses forces et ses faiblesses avant de prendre une décision.