2026-08-06 15:01:56 +00:00
from datetime import datetime , timedelta , timezone
from typing import Optional
from fastapi import Depends , HTTPException , status
from fastapi . security import OAuth2PasswordBearer
from jose import JWTError , jwt
from passlib . context import CryptContext
from pydantic import BaseModel
SECRET_KEY = " change-me-in-production "
ALGORITHM = " HS256 "
ACCESS_TOKEN_EXPIRE_MINUTES = 120
pwd_context = CryptContext ( schemes = [ " bcrypt " ] , deprecated = " auto " )
oauth2_scheme = OAuth2PasswordBearer ( tokenUrl = " /auth/token " )
class Token ( BaseModel ) :
access_token : str
token_type : str = " bearer "
class TokenData ( BaseModel ) :
username : Optional [ str ] = None
class User ( BaseModel ) :
username : str
disabled : bool = False
role : str = " viewer "
fake_users_db = {
" admin " : {
" username " : " admin " ,
" hashed_password " : " $2b$12$j2rrsvzYhC9lQ4w6WJ1wPeY9CKEMMvmFo0xSg6u40qCMgfHdCqkfG " ,
" disabled " : False ,
" role " : " admin " ,
} ,
" viewer " : {
" username " : " viewer " ,
" hashed_password " : " $2b$12$DA7Nn4MVSr1m3Q0P6x1Qe.i6yd0qJ7Yx1C2VYLRNvKcJsteVEh9W6 " ,
" disabled " : False ,
" role " : " viewer " ,
} ,
}
def verify_password ( plain_password : str , hashed_password : str ) - > bool :
return pwd_context . verify ( plain_password , hashed_password )
def get_user ( username : str ) :
user = fake_users_db . get ( username )
if not user :
return None
return User ( username = user [ " username " ] , disabled = user [ " disabled " ] , role = user [ " role " ] )
def authenticate_user ( username : str , password : str ) :
user_dict = fake_users_db . get ( username )
if not user_dict :
return None
if not pwd_context . verify ( password , user_dict [ " hashed_password " ] ) :
return None
return User ( username = user_dict [ " username " ] , disabled = user_dict [ " disabled " ] , role = user_dict [ " role " ] )
def create_access_token ( data : dict , expires_delta : Optional [ timedelta ] = None ) - > str :
to_encode = data . copy ( )
expire = datetime . now ( timezone . utc ) + ( expires_delta or timedelta ( minutes = ACCESS_TOKEN_EXPIRE_MINUTES ) )
to_encode . update ( { " exp " : expire } )
return jwt . encode ( to_encode , SECRET_KEY , algorithm = ALGORITHM )
def get_current_user ( token : str = Depends ( oauth2_scheme ) ) - > User :
credentials_exception = HTTPException ( status_code = status . HTTP_401_UNAUTHORIZED , detail = " Could not validate credentials " , headers = { " WWW-Authenticate " : " Bearer " } )
try :
payload = jwt . decode ( token , SECRET_KEY , algorithms = [ ALGORITHM ] )
username : str = payload . get ( " sub " )
if username is None :
raise credentials_exception
token_data = TokenData ( username = username )
except JWTError :
raise credentials_exception
user = get_user ( token_data . username )
if user is None :
raise credentials_exception
return user
def get_current_active_user ( current_user : User = Depends ( get_current_user ) ) - > User :
if current_user . disabled :
raise HTTPException ( status_code = 400 , detail = " Inactive user " )
return current_user