hisham-cmd's picture
Upload auth.py
d5ea479 verified
Raw
History Blame Contribute Delete
4.66 kB
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from jose import jwt, JWTError
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
import uuid
from datetime import datetime
from database.session import get_db
from database.models import User
from schemas import UserCreate, User as UserSchema, Token, UserLogin
from auth_utils import get_password_hash, verify_password, create_access_token, SECRET_KEY, ALGORITHM
router = APIRouter(prefix="/auth", tags=["Authentication"])
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="auth/login")
async def get_current_user(
token: str = Depends(oauth2_scheme),
db: AsyncSession = Depends(get_db)
) -> 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])
user_id: str = payload.get("sub")
if user_id is None:
raise credentials_exception
except JWTError:
raise credentials_exception
result = await db.execute(select(User).where(User.id == uuid.UUID(user_id)))
user = result.scalars().first()
if user is None:
raise credentials_exception
if not user.is_active:
raise HTTPException(status_code=400, detail="Inactive user")
return user
@router.post("/register", response_model=UserSchema, status_code=status.HTTP_201_CREATED)
async def register(user_in: UserCreate, db: AsyncSession = Depends(get_db)):
# Check if user exists
result = await db.execute(select(User).where(User.email == user_in.email))
if result.scalars().first():
raise HTTPException(
status_code=400,
detail="User with this email already exists"
)
result = await db.execute(select(User).where(User.username == user_in.username))
if result.scalars().first():
raise HTTPException(
status_code=400,
detail="User with this username already exists"
)
# Create user
db_user = User(
email=user_in.email,
username=user_in.username,
name=user_in.name,
password_hash=get_password_hash(user_in.password),
role="USER",
status="active",
balance=0.0000,
spent=0.0000
)
db.add(db_user)
await db.commit()
await db.refresh(db_user)
return db_user
@router.post("/login", response_model=Token)
async def login(user_in: UserLogin, db: AsyncSession = Depends(get_db)):
result = await db.execute(select(User).where(User.email == user_in.email))
user = result.scalars().first()
if not user or not verify_password(user_in.password, user.password_hash):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect email or password",
headers={"WWW-Authenticate": "Bearer"},
)
if not user.is_active:
raise HTTPException(status_code=400, detail="Inactive user")
access_token = create_access_token(subject=user.id)
return {"access_token": access_token, "token_type": "bearer"}
@router.post("/token", response_model=Token)
async def login_for_access_token(form_data: OAuth2PasswordRequestForm = Depends(), db: AsyncSession = Depends(get_db)):
# Supports standard OAuth2 form login (username/password)
result = await db.execute(select(User).where(User.username == form_data.username))
user = result.scalars().first()
if not user or not verify_password(form_data.password, user.password_hash):
# Fallback to checking by email if username check failed
result = await db.execute(select(User).where(User.email == form_data.username))
user = result.scalars().first()
if not user or not verify_password(form_data.password, user.password_hash):
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Incorrect username or password",
headers={"WWW-Authenticate": "Bearer"},
)
access_token = create_access_token(subject=user.id)
return {"access_token": access_token, "token_type": "bearer"}
@router.get("/me", response_model=UserSchema)
async def read_users_me(current_user: User = Depends(get_current_user)):
return current_user