Tangerine-Auth是一個Python庫,可為用戶身份驗證和安全處理密鑰和加密數據提供實用程序。它使用bcrypt進行密碼哈希和JWT進行基於令牌的身份驗證。
注意:橘色實施目前正在Beta中。不建議完全用於生產使用。同時,請隨時下載並隨身攜帶!我們正在努力添加更多測試和文檔。如果您發現任何錯誤或有任何建議,請在Github上打開問題。
使用PIP安裝軟件包:
pip install tangerine-auth將Yuzu集成到您的應用程序中的一般步驟如下:
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' ]}創建一個鑰匙扣對象並將其傳遞給Yuzu構造函數。鑰匙扣對像用於安全處理密鑰和加密數據。您可以使用鍵盤對像對數據進行加密和解密數據,並存儲和檢索密鑰。
創建Yuzu對象並將其傳遞給鍵 - lime對象,數據庫中的用戶的功能以及在數據庫中創建用戶的功能。
(可選)Yuzu使用bcrypt進行哈希密碼。您可以選擇將自定義哈希功能傳遞給Yuzu構造函數。自定義哈希功能應將密碼字符串作為參數,然後返回哈希的密碼字符串。
步驟3完成後,您現在可以使用Yuzu對象註冊新用戶,登錄用戶,註銷用戶並驗證身份驗證令牌。
Yuzu曾與燒瓶和橘子一起工作,目前有兩個與Yuzu捆綁在一起的JWT Middlewares,一個用於燒瓶,一個用於橘子。一旦正確初始化了Yuzu類,就可以通過致電:
app . use ( auth . jwt_middleware ).燒瓶版本JWT中間件仍然是實驗性的,並且可能容易出現問題。在對其進行更徹底的測試之前,不建議將其用於生產。 JWT中間件在燒瓶中的作用有些不同,將其與燒瓶一起使用,您將其用作裝飾器:
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 )注意:驗證中間件將用戶數據附加到CTX對象。您可以通過致電訪問路由處理程序中的用戶數據
ctx . auth . user or ctx . get ( "user" )Yuzu是提供用戶身份驗證功能的類。它使用bcrypt進行密碼哈希和JWT來創建和驗證身份驗證令牌。
以下是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是一個提供安全處理密鑰和加密數據的功能的類。
以下是鑰匙扣類的關鍵方法:
- `__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 .為此,您要編寫兩個功能,一個用於在所選數據庫系統中找到用戶,一個用於在所選數據庫系統中創建用戶。這些功能應將用戶數據的字典作為參數,並返回用戶數據的字典。用戶數據字典至少應包含電子郵件和密碼字段。用戶數據字典可以包含您要存儲在數據庫中的任何其他字段。
這是如何使用yuzu和鑰匙液類的示例:
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旨在靈活,使您可以根據項目的特定需求進行調整。您可以自定義其行為的一種方法是更改默認密碼和驗證功能。
默認情況下,Yuzu使用bcrypt庫進行密碼哈希和驗證。如果要使用其他方法,則可以將自己的哈希和驗證功能傳遞給Yuzu類構造函數。這是一個如何做的示例:
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 )將Argon2用於Hashing Argon2是一種現代,安全的密碼哈希算法,密碼哈希競賽推薦。這是如何與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 )這些示例允許您從默認的BCrypt算法切換到SHA256或Argon2。您還可以根據您的特定要求來修改這些功能,以更改哈希功能的難度(例如,通過增加迭代次數或內存使用量)。
請記住,更改這些功能可能會對您的應用程序的安全性產生影響。在做出決定之前,您應該了解所選哈希功能及其優勢和劣勢的工作。