import os import bcrypt from datetime import datetime, timedelta from typing import Optional from jose import JWTError, jwt from fastapi import Depends, HTTPException, status from fastapi.security import OAuth2PasswordBearer from sqlalchemy.orm import Session from database import get_db import models SECRET_KEY = os.getenv("SECRET_KEY", "changeme") ALGORITHM = "HS256" ACCESS_TOKEN_EXPIRE_HOURS = 24 oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/api/auth/login") def hash_password(password: str) -> str: """비밀번호 bcrypt 해시 생성""" salt = bcrypt.gensalt(rounds=12) return bcrypt.hashpw(password.encode("utf-8"), salt).decode("utf-8") def verify_password(plain: str, hashed: str) -> bool: """비밀번호 검증""" try: return bcrypt.checkpw(plain.encode("utf-8"), hashed.encode("utf-8")) except Exception: return False def create_access_token(data: dict, expires_delta: Optional[timedelta] = None) -> str: to_encode = data.copy() expire = datetime.utcnow() + (expires_delta or timedelta(hours=ACCESS_TOKEN_EXPIRE_HOURS)) to_encode.update({"exp": expire}) return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM) def get_current_user( token: str = Depends(oauth2_scheme), db: Session = Depends(get_db) ) -> models.User: credentials_exception = HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="인증 정보가 유효하지 않습니다.", 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 user = db.query(models.User).filter( models.User.id == int(user_id), models.User.is_active == True ).first() if user is None: raise credentials_exception return user def require_role(*roles): def checker(current_user: models.User = Depends(get_current_user)): if current_user.role not in roles: raise HTTPException(status_code=403, detail="권한이 없습니다.") return current_user return checker require_admin = require_role("admin") require_mechanic = require_role("mechanic", "admin") require_manufacturer = require_role("manufacturer", "admin")