Tangerine-Auth adalah perpustakaan Python yang menyediakan utilitas untuk otentikasi pengguna dan penanganan kunci yang aman dan data terenkripsi. Ini menggunakan bcrypt untuk hashing kata sandi dan jwt untuk otentikasi berbasis token.
Catatan: Tangerine-Auth saat ini dalam beta. Belum disarankan untuk penggunaan produksi. Sementara itu, silakan mengunduh dan bermain -main dengannya! Kami sedang berupaya menambahkan lebih banyak tes dan dokumentasi. Jika Anda menemukan bug atau memiliki saran, silakan buka masalah di GitHub.
Gunakan PIP untuk menginstal paket:
pip install tangerine-authLangkah umum untuk mengintegrasikan Yuzu ke dalam aplikasi Anda adalah sebagai berikut:
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' ]}Buat objek KeyLime dan berikan ke konstruktor Yuzu. Objek KeyLime digunakan untuk menangani kunci dengan aman dan data terenkripsi. Anda dapat menggunakan objek KeyLime untuk mengenkripsi dan mendekripsi data, dan untuk menyimpan dan mengambil kunci.
Buat objek Yuzu dan lewati objek KeyLime, fungsi untuk menemukan pengguna di database Anda, dan fungsi untuk membuat pengguna di database Anda.
(Opsional) Yuzu menggunakan bcrypt untuk kata sandi hash. Anda secara opsional dapat meneruskan fungsi hash khusus ke konstruktor Yuzu. Fungsi hash khusus harus mengambil string kata sandi sebagai argumen dan mengembalikan string kata sandi hash.
Setelah langkah 3 selesai, Anda sekarang dapat menggunakan objek Yuzu untuk mendaftar pengguna baru, masuk ke pengguna, keluar dari pengguna, dan memverifikasi token otentikasi.
Yuzu dibangun untuk bekerja dengan Flask serta Tangerine, saat ini ada dua JWT Middlewares yang dibundel dengan Yuzu, satu untuk Flask dan satu untuk Tangerine. Setelah Anda menginisialisasi kelas Yuzu dengan benar, Anda dapat menggunakan Middleware Tangerine dengan menelepon:
app . use ( auth . jwt_middleware ).Versi Flask JWT Middleware masih eksperimental dan, bisa rentan terhadap masalah. Ini tidak akan direkomendasikan untuk penggunaan produksi sampai diuji lebih teliti. Middleware JWT bekerja sedikit berbeda dalam labu, untuk menggunakannya dengan flask, Anda menggunakannya sebagai dekorator:
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 )Catatan: Auth Middleware menambahkan data pengguna ke objek CTX. Anda dapat mengakses data pengguna di pawang rute Anda dengan menelepon
ctx . auth . user or ctx . get ( "user" )Yuzu adalah kelas yang menyediakan fungsionalitas otentikasi pengguna. Ini menggunakan bcrypt untuk hashing kata sandi dan jwt untuk membuat dan memverifikasi token otentikasi.
Di bawah ini adalah metode utama kelas 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 adalah kelas yang menyediakan fungsionalitas untuk menangani kunci dengan aman dan data terenkripsi.
Di bawah ini adalah metode utama kelas 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 .Conept umum untuk ini adalah Anda ingin menulis dua fungsi, satu untuk menemukan pengguna di sistem basis data yang Anda pilih, dan satu untuk membuat pengguna dalam sistem basis data yang Anda pilih. Fungsi -fungsi ini harus mengambil kamus data pengguna sebagai argumen dan mengembalikan kamus data pengguna. Kamus data pengguna harus berisi setidaknya email dan bidang kata sandi. Kamus Data Pengguna dapat berisi bidang lain yang ingin Anda simpan di database Anda.
Berikut adalah contoh cara menggunakan kelas Yuzu dan 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 dirancang agar fleksibel, memungkinkan Anda untuk menyesuaikannya dengan kebutuhan spesifik proyek Anda. Salah satu cara di mana Anda dapat menyesuaikan perilakunya adalah dengan mengubah fungsi hashing dan verifikasi kata sandi default.
Secara default, Yuzu menggunakan pustaka bcrypt untuk hashing dan verifikasi kata sandi. Jika Anda ingin menggunakan pendekatan yang berbeda, Anda dapat melewati fungsi hashing dan verifikasi Anda sendiri ke konstruktor kelas Yuzu. Berikut adalah contoh cara melakukannya:
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 )Menggunakan argon2 untuk hashing argon2 adalah algoritma hashing kata sandi modern yang direkomendasikan oleh kompetisi hashing kata sandi. Berikut adalah contoh cara menggunakannya dengan 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 )Contoh -contoh ini memungkinkan Anda untuk beralih dari algoritma BCRYPT default ke SHA256 atau Argon2. Anda juga dapat memodifikasi fungsi -fungsi ini untuk mengubah kesulitan fungsi hash (misalnya, dengan meningkatkan jumlah iterasi atau penggunaan memori) sesuai persyaratan spesifik Anda.
Ingatlah bahwa mengubah fungsi -fungsi ini dapat memiliki implikasi untuk keamanan aplikasi Anda. Anda harus memahami cara kerja fungsi hash yang dipilih dan kekuatan serta kelemahannya sebelum membuat keputusan.