from sqlalchemy.orm import Session from datetime import datetime from typing import Optional from app.models.user import User, UserRole from app.schemas.auth import UserRegister, Token from app.utils.security import hash_password, verify_password from app.utils.jwt_handler import create_access_token, create_refresh_token from app.utils.exceptions import AuthenticationError, ConflictError class AuthService: """인증 관련 비즈니스 로직""" @staticmethod def register_user(db: Session, user_data: UserRegister) -> User: """사용자 등록""" # 중복 체크 if db.query(User).filter(User.username == user_data.username).first(): raise ConflictError("이미 존재하는 사용자명입니다") if db.query(User).filter(User.email == user_data.email).first(): raise ConflictError("이미 존재하는 이메일입니다") # 새 사용자 생성 new_user = User( username=user_data.username, email=user_data.email, hashed_password=hash_password(user_data.password), full_name=user_data.full_name, role=UserRole.USER ) db.add(new_user) db.commit() db.refresh(new_user) return new_user @staticmethod def authenticate_user(db: Session, username: str, password: str) -> User: """사용자 인증""" user = db.query(User).filter(User.username == username).first() if not user: raise AuthenticationError("사용자를 찾을 수 없습니다") if not user.is_active: raise AuthenticationError("비활성화된 계정입니다") if not verify_password(password, user.hashed_password): raise AuthenticationError("비밀번호가 일치하지 않습니다") # 마지막 로그인 시간 업데이트 user.last_login = datetime.utcnow() db.commit() return user @staticmethod def create_tokens(user: User) -> Token: """JWT 토큰 생성""" token_data = { "sub": str(user.id), "username": user.username, "role": user.role.value } access_token = create_access_token(token_data) refresh_token = create_refresh_token(token_data) return Token( access_token=access_token, refresh_token=refresh_token, token_type="bearer", expires_in=1800 # 30분 ) @staticmethod def get_user_by_id(db: Session, user_id: int) -> Optional[User]: """사용자 ID로 조회""" return db.query(User).filter(User.id == user_id).first() @staticmethod def get_user_by_username(db: Session, username: str) -> Optional[User]: """사용자명으로 조회""" return db.query(User).filter(User.username == username).first() auth_service = AuthService()