Tangerine-Auth는 사용자 인증을위한 유틸리티를 제공하고 키 및 암호화 된 데이터의 보안 처리를위한 유틸리티를 제공하는 Python 라이브러리입니다. 비밀번호 해싱에는 BCrypt를 사용하고 토큰 기반 인증에는 JWT를 사용합니다.
참고 : Tangerine-Auth는 현재 베타 버전에 있습니다. 아직 생산 사용에는 권장되지 않습니다. 그 동안 자유롭게 다운로드하고 놀아주십시오! 우리는 더 많은 테스트와 문서를 추가하기 위해 노력하고 있습니다. 버그가 있거나 제안이 있으면 GitHub에서 문제를여십시오.
PIP를 사용하여 패키지를 설치하십시오.
pip install tangerine-authYuzu를 응용 프로그램에 통합하는 일반적인 단계는 다음과 같습니다.
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' ]}키일 리임 객체를 만들어 유즈 생성자에게 전달하십시오. Keylime 객체는 키 및 암호화 된 데이터를 안전하게 처리하는 데 사용됩니다. 키일 라임 객체를 사용하여 데이터를 암호화 및 해독하고 키를 저장하고 검색 할 수 있습니다.
Yuzu 객체를 생성하고 Keylime 객체, 데이터베이스에서 사용자를 찾는 기능 및 데이터베이스에서 사용자를 생성하는 기능을 전달하십시오.
(선택 사항) Yuzu는 Bcrypt to Hash 비밀번호를 사용합니다. 선택적으로 사용자 정의 해시 함수를 Yuzu 생성자에게 전달할 수 있습니다. 사용자 정의 해시 함수는 암호 문자열을 인수로 가져 와서 해시 암호 문자열을 반환해야합니다.
3 단계가 완료되면 Yuzu 객체를 사용하여 새 사용자 가입, 사용자 로그인하고 사용자 로그인 한 다음 인증 토큰을 확인할 수 있습니다.
Yuzu는 Tangerine뿐만 아니라 Flask와 함께 작동하도록 제작되었으며 현재 Yuzu, 플라스크 용 및 Tangerine 용 2 개의 JWT 중간 전야가 있습니다. Yuzu 클래스를 올바르게 초기화 한 후에는 다음을 호출하여 Tangerine Middleware를 사용할 수 있습니다.
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 )참고 : Auth Middleware는 사용자 데이터를 CTX 객체에 추가합니다. 전화를 통해 경로 핸들러의 사용자 데이터에 액세스 할 수 있습니다.
ctx . auth . user or ctx . get ( "user" )Yuzu는 사용자 인증 기능을 제공하는 클래스입니다. 인증 토큰을 작성하고 확인하기 위해 암호 해싱 및 JWT 용 BCrypt를 사용합니다.
다음은 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 .Kyylime은 키 및 암호화 된 데이터를 안전하게 처리 할 수있는 기능을 제공하는 클래스입니다.
다음은 Kyylime 클래스의 주요 방법입니다.
- `__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는 선택한 데이터베이스 시스템에서 사용자를 찾기위한 두 가지 기능과 선택한 데이터베이스 시스템에서 사용자를 작성하기위한 두 가지 기능을 작성하려는 것입니다. 이러한 기능은 사용자 데이터 사전을 인수로 취하고 사용자 데이터 사전을 반환해야합니다. 사용자 데이터 사전에는 최소한 이메일 및 비밀번호 필드가 포함되어야합니다. 사용자 데이터 사전에는 데이터베이스에 저장하려는 다른 필드가 포함될 수 있습니다.
다음은 Yuzu 및 Kyylime 클래스 사용 방법의 예입니다.
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를 사용하는 것은 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로 전환 할 수 있습니다. 또한 특정 요구 사항에 따라 해시 함수의 난이도 (예 : 반복 횟수 또는 메모리 사용량)를 변경하도록 이러한 함수를 수정할 수도 있습니다.
이러한 기능을 변경하면 응용 프로그램의 보안에 영향을 줄 수 있습니다. 결정을 내리기 전에 선택한 해시 기능의 작업과 그 강점과 약점을 이해해야합니다.