Post
[Python 2/6] 회원 도메인 구현: User 모델 + 비밀번호 해싱
[Python 2/6] 회원 도메인 구현: User 모델 + 비밀번호 해싱
1) 패키지 추가
pip install passlib[bcrypt]
2) 모델 정의
app/models.py
from sqlalchemy import Boolean, Column, DateTime, Integer, String, func
from app.db import Base
class User(Base):
__tablename__ = 'users'
id = Column(Integer, primary_key=True, index=True)
email = Column(String, unique=True, index=True, nullable=False)
name = Column(String, nullable=False)
password_hash = Column(String, nullable=False)
is_active = Column(Boolean, default=True)
created_at = Column(DateTime(timezone=True), server_default=func.now())
3) 스키마
app/schemas.py
from pydantic import BaseModel, EmailStr
class UserCreate(BaseModel):
email: EmailStr
name: str
password: str
class UserOut(BaseModel):
id: int
email: EmailStr
name: str
class Config:
from_attributes = True
4) 보안 유틸
app/security.py
from passlib.context import CryptContext
pwd_context = CryptContext(schemes=['bcrypt'], deprecated='auto')
def hash_password(password: str) -> str:
return pwd_context.hash(password)
def verify_password(plain: str, hashed: str) -> bool:
return pwd_context.verify(plain, hashed)
5) 회원가입 라우터
app/routers/auth.py
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.orm import Session
from app.db import get_db
from app.models import User
from app.schemas import UserCreate, UserOut
from app.security import hash_password
router = APIRouter(prefix='/auth', tags=['auth'])
@router.post('/register', response_model=UserOut)
def register(payload: UserCreate, db: Session = Depends(get_db)):
if db.query(User).filter(User.email == payload.email).first():
raise HTTPException(status_code=400, detail='이미 사용 중인 이메일입니다.')
user = User(
email=payload.email,
name=payload.name,
password_hash=hash_password(payload.password)
)
db.add(user)
db.commit()
db.refresh(user)
return user
6) main.py 연결 + 테이블 생성
app/main.py
from fastapi import FastAPI
from app.db import Base, engine
from app.routers.health import router as health_router
from app.routers.auth import router as auth_router
Base.metadata.create_all(bind=engine)
app = FastAPI(title='Todo Backend')
app.include_router(health_router)
app.include_router(auth_router)
댓글