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

JWT 로그인과 인증 미들웨어/의존성

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

22강. JWT 로그인과 인증 미들웨어/의존성

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

서버는 각 기록 요청이 어떤 사용자에게서 왔는지 알 수 없습니다. 로그인에서 JWT를 발급하고 Bearer token으로 현재 사용자를 확인합니다.

2. 학습 목표

3. 핵심 개념

JWT는 내용을 숨기는 암호문이 아니라 서명된 token입니다. 비밀 정보를 payload에 넣지 않고 sub에는 앱 전체에서 고유한 문자열 식별자를 넣습니다. exp가 지나면 거부하며 HTTPS 없이 token을 전송해서는 안 됩니다. 인증은 여러 endpoint가 재사용하므로 middleware보다 값을 반환하는 dependency가 잘 맞습니다.

4. 단계별 코드 예시

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

app/schemas/token.py
from pydantic import BaseModel


class Token(BaseModel):
access_token: str
token_type: str = "bearer"

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

app/security.py
from datetime import datetime, timedelta, timezone

import jwt
from jwt.exceptions import InvalidTokenError

from app.config import settings

ALGORITHM = "HS256"


def create_access_token(subject: str) -> str:
expires_at = datetime.now(timezone.utc) + timedelta(minutes=settings.access_token_expire_minutes)
return jwt.encode({"sub": subject, "exp": expires_at}, settings.jwt_secret, algorithm=ALGORITHM)

파일 경로: game-ranking-api/app/dependencies.py에 추가

app/dependencies.py
from typing import Annotated

import jwt
from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer
from jwt.exceptions import InvalidTokenError
from sqlalchemy.orm import Session

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/auth/token")


def get_current_user(
token: Annotated[str, Depends(oauth2_scheme)],
db: Annotated[Session, Depends(get_db)],
) -> User:
credentials_error = HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="유효한 인증 정보가 필요합니다",
headers={"WWW-Authenticate": "Bearer"},
)
try:
payload = jwt.decode(token, settings.jwt_secret, algorithms=[ALGORITHM])
subject = payload.get("sub")
user_id = int(subject) if subject is not None else None
except (InvalidTokenError, ValueError):
raise credentials_error
user = db.get(User, user_id)
if user is None:
raise credentials_error
return user

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

app/routers/auth.py
from typing import Annotated

from fastapi import Depends
from fastapi.security import OAuth2PasswordRequestForm


@router.post("/token", response_model=Token)
def login(
form: Annotated[OAuth2PasswordRequestForm, Depends()],
db: DbSession,
) -> Token:
user = db.scalar(select(User).where(User.username == form.username.lower()))
if user is None or not verify_password(form.password, user.password_hash):
raise HTTPException(status_code=401, detail="사용자 이름 또는 비밀번호가 올바르지 않습니다")
return Token(access_token=create_access_token(str(user.id)))

실행 위치: game-ranking-api/

python -m uvicorn app.main:app --reload
$token = (Invoke-RestMethod -Method Post http://127.0.0.1:8000/auth/token -ContentType 'application/x-www-form-urlencoded' -Body 'username=player_one&password=correct-horse-battery').access_token
Invoke-RestMethod http://127.0.0.1:8000/users/me -Headers @{Authorization="Bearer $token"}

5. 코드가 동작하는 이유

로그인이 비밀번호를 verify한 뒤 user id와 만료 시간을 서명합니다. 인증 dependency가 Bearer token을 추출하고 허용 알고리즘을 고정해 decode한 다음 DB에서 현재 사용자를 다시 조회합니다. 삭제된 사용자 token도 이 단계에서 거부됩니다.

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

7. 직접 실습

8. 이해 점검 질문 3개

9. 핵심 요약

MINI QUIZ

JWT 로그인과 인증 미들웨어/의존성 미니 퀴즈

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

0 / 2
  1. 문제 1“JWT 로그인과 인증 미들웨어/의존성”의 위험한 선택을 피하려면 어떤 원칙을 적용해야 하나요?
  2. 문제 2‘decode에서 token의 alg 값을 그대로 신뢰합니다.’ 실수를 판단할 때 “JWT 로그인과 인증 미들웨어/의존성” 강의가 제시한 기준은 무엇인가요?
LESSON STATUS

학습을 마쳤나요?

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

22강. JWT 로그인과 인증 미들웨어/의존성 미완료 상태