본문으로 건너뛰기
백엔드 기초집: Python FastAPILESSON 21

비밀번호 해싱과 사용자 회원가입

난이도초급
예상 시간35분
선수지식이전 강의

21강. 비밀번호 해싱과 사용자 회원가입

1. 이번 강의에서 해결할 문제

회원가입 비밀번호를 그대로 DB에 저장하면 유출 시 즉시 계정 피해로 이어집니다. 복호화할 수 없는 password hash만 저장합니다.

2. 학습 목표

3. 핵심 개념

비밀번호는 복호화할 이유가 없으므로 salt가 포함된 느린 단방향 해시로 저장합니다. FastAPI 공식 JWT 예제는 현재 pwdlib의 권장 설정을 사용하며 Argon2를 지원합니다. 로그인에서는 평문을 다시 hash해 문자열 비교하지 않고 verify(plain, hash)를 호출합니다.

4. 단계별 코드 예시

파일 경로: game-ranking-api/app/schemas/user.py

app/schemas/user.py
from pydantic import BaseModel, ConfigDict, Field


class UserCreate(BaseModel):
username: str = Field(min_length=3, max_length=50, pattern=r"^[a-zA-Z0-9_]+$")
password: str = Field(min_length=12, max_length=128)


class UserRead(BaseModel):
model_config = ConfigDict(from_attributes=True)
id: int
username: str
role: str

파일 경로: game-ranking-api/app/security.py

app/security.py
from pwdlib import PasswordHash

password_hash = PasswordHash.recommended()


def hash_password(password: str) -> str:
return password_hash.hash(password)


def verify_password(password: str, encoded_hash: str) -> bool:
return password_hash.verify(password, encoded_hash)

파일 경로: game-ranking-api/app/routers/auth.py

app/routers/auth.py
from fastapi import APIRouter, HTTPException, status
from sqlalchemy import select

from app.models.user import User
from app.schemas.user import UserCreate, UserRead
from app.security import hash_password

router = APIRouter(prefix="/auth", tags=["auth"])


@router.post("/register", response_model=UserRead, status_code=status.HTTP_201_CREATED)
def register(payload: UserCreate, db: DbSession) -> User:
username = payload.username.lower()
if db.scalar(select(User).where(User.username == username)):
raise HTTPException(status_code=409, detail="이미 사용 중인 사용자 이름입니다")

user = User(username=username, password_hash=hash_password(payload.password))
db.add(user)
db.commit()
db.refresh(user)
return user

실행 위치: game-ranking-api/

python -m uvicorn app.main:app --reload
Invoke-RestMethod -Method Post http://127.0.0.1:8000/auth/register -ContentType 'application/json' -Body '{"username":"player_one","password":"correct-horse-battery"}'

5. 코드가 동작하는 이유

회원가입 입력의 password는 함수 안에서만 사용되고 DB에는 Argon2 형식 hash가 저장됩니다. UserRead에는 password_hash 필드가 없으므로 응답에서 필터링됩니다. username을 소문자로 정규화해 대소문자만 다른 중복을 줄입니다.

6. 자주 하는 실수와 해결법

7. 직접 실습

8. 이해 점검 질문 3개

9. 핵심 요약

MINI QUIZ

비밀번호 해싱과 사용자 회원가입 미니 퀴즈

선택 즉시 정답과 해설을 확인할 수 있습니다. 결과는 이 브라우저에만 저장됩니다.

0 / 2
  1. 문제 1“비밀번호 해싱과 사용자 회원가입” 실습을 안전하게 진행하기 위한 판단으로 가장 알맞은 것은 무엇인가요?
  2. 문제 2“비밀번호 해싱과 사용자 회원가입”에서 ‘password_hash를 response model에 넣습니다.’ 문제가 생겼습니다. 가장 알맞은 진단 또는 대응은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

직접 실습과 점검 질문까지 확인한 뒤 완료로 표시하세요.

21강. 비밀번호 해싱과 사용자 회원가입 미완료 상태