from fastapi import APIRouter, Depends, HTTPException, status from fastapi.security import OAuth2PasswordRequestForm from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from typing import Annotated from app.core.database import get_db from app.core.security import verify_password, get_password_hash, create_access_token, create_refresh_token, decode_token from app.models.user import User from app.schemas.user import UserCreate, UserResponse, TokenResponse from app.deps import CurrentUser router = APIRouter(prefix="/auth", tags=["인증"]) @router.post("/register", response_model=UserResponse, status_code=status.HTTP_201_CREATED) async def register(data: UserCreate, db: Annotated[AsyncSession, Depends(get_db)]): result = await db.execute(select(User).where(User.email == data.email)) if result.scalar_one_or_none(): raise HTTPException(status_code=400, detail="이미 등록된 이메일입니다") user = User( email=data.email, hashed_password=get_password_hash(data.password), name=data.name, role=data.role, phone=data.phone, ) db.add(user) await db.commit() await db.refresh(user) return user @router.post("/login", response_model=TokenResponse) async def login( form_data: Annotated[OAuth2PasswordRequestForm, Depends()], db: Annotated[AsyncSession, Depends(get_db)], ): result = await db.execute(select(User).where(User.email == form_data.username, User.is_active == True)) user = result.scalar_one_or_none() if not user or not verify_password(form_data.password, user.hashed_password): raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="이메일 또는 비밀번호가 올바르지 않습니다", headers={"WWW-Authenticate": "Bearer"}, ) return TokenResponse( access_token=create_access_token(str(user.id)), refresh_token=create_refresh_token(str(user.id)), user=UserResponse.model_validate(user), ) @router.post("/refresh", response_model=TokenResponse) async def refresh_token(refresh_token_str: str, db: Annotated[AsyncSession, Depends(get_db)]): payload = decode_token(refresh_token_str) if not payload or payload.get("type") != "refresh": raise HTTPException(status_code=401, detail="유효하지 않은 리프레시 토큰입니다") result = await db.execute(select(User).where(User.id == payload["sub"], User.is_active == True)) user = result.scalar_one_or_none() if not user: raise HTTPException(status_code=401, detail="사용자를 찾을 수 없습니다") return TokenResponse( access_token=create_access_token(str(user.id)), refresh_token=create_refresh_token(str(user.id)), user=UserResponse.model_validate(user), ) @router.get("/me", response_model=UserResponse) async def get_me(current_user: CurrentUser): return current_user