oraculo_api / app /core /security.py
Diiegoal's picture
Actualizo la app
d623240
Raw
History Blame Contribute Delete
2.21 kB
from __future__ import annotations
from datetime import datetime, timedelta, timezone
import hashlib
from typing import Any
import bcrypt
import jwt
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
from pydantic import BaseModel
from app.core.config import Settings
from app.core.exceptions import AuthenticationError
bearer_scheme = HTTPBearer(auto_error=False)
class TokenPayload(BaseModel):
sub: str
role: str = "user"
exp: int
def hash_password(password: str) -> str:
password_bytes = _password_to_bytes(password)
return bcrypt.hashpw(password_bytes, bcrypt.gensalt()).decode("utf-8")
def verify_password(plain_password: str, hashed_password: str) -> bool:
password_bytes = _password_to_bytes(plain_password)
return bcrypt.checkpw(password_bytes, hashed_password.encode("utf-8"))
def _password_to_bytes(password: str) -> bytes:
raw_bytes = password.encode("utf-8")
if len(raw_bytes) <= 72:
return raw_bytes
return hashlib.sha256(raw_bytes).hexdigest().encode("utf-8")
def create_access_token(
*,
subject: str,
role: str,
settings: Settings,
expires_delta: timedelta | None = None,
) -> str:
expire_at = datetime.now(timezone.utc) + (
expires_delta or timedelta(minutes=settings.access_token_expire_minutes)
)
payload: dict[str, Any] = {
"sub": subject,
"role": role,
"exp": expire_at,
}
return jwt.encode(payload, settings.jwt_secret_key, algorithm=settings.jwt_algorithm)
def decode_access_token(token: str, settings: Settings) -> TokenPayload:
try:
payload = jwt.decode(token, settings.jwt_secret_key, algorithms=[settings.jwt_algorithm])
return TokenPayload(**payload)
except jwt.ExpiredSignatureError as exc:
raise AuthenticationError("Access token expired.") from exc
except jwt.PyJWTError as exc:
raise AuthenticationError("Invalid access token.") from exc
def extract_bearer_token(credentials: HTTPAuthorizationCredentials | None) -> str:
if credentials is None or not credentials.credentials:
raise AuthenticationError("Missing bearer token.")
return credentials.credentials