Files
fastapi/app/auth.py
T
2026-07-16 16:06:22 +03:00

80 lines
2.7 KiB
Python

from datetime import datetime, timedelta
from typing import Optional
from fastapi import Depends, HTTPException, status
from jose import jwt, JWTError
from fastapi.security import OAuth2PasswordBearer
import bcrypt
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from app.models import User
from app.schemas import Token
from app.db import get_db
import os
# Загружаем переменные окружения
SECRET_KEY = os.getenv("SECRET_KEY")
ALGORITHM = os.getenv("ALGORITHM", "HS256")
ACCESS_TOKEN_EXPIRE_MINUTES = int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", "60"))
# ---------------------------------------------------------
# Хэширование пароля
# ---------------------------------------------------------
def hash_password(password: str) -> str:
pwd_bytes = password.encode('utf-8')
salt = bcrypt.gensalt()
return bcrypt.hashpw(pwd_bytes, salt).decode('utf-8')
def verify_password(plain_password: str, hashed_password: str) -> bool:
return bcrypt.checkpw(
plain_password.encode('utf-8'),
hashed_password.encode('utf-8')
)
# ---------------------------------------------------------
# Создание JWT-токена
# ---------------------------------------------------------
def create_access_token(data: dict, expires_delta: Optional[int] = None):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(
minutes=expires_delta or ACCESS_TOKEN_EXPIRE_MINUTES
)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
# ---------------------------------------------------------
# Получение текущего пользователя по токену
# ---------------------------------------------------------
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_db)
):
""" Достаём токен из Authorization Bearer """
if not token or not isinstance(token, str):
raise HTTPException(status_code=401, detail="Missing token")
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
email: str = payload.get("sub")
if email is None:
raise HTTPException(status_code=401, detail="Invalid token payload")
except JWTError:
raise HTTPException(status_code=401, detail="Invalid or expired token")
query = select(User).where(User.email == email)
result = await db.execute(query)
user = result.scalar_one_or_none()
if user is None:
raise HTTPException(status_code=404, detail="User not found")
return user