파이썬 FastAPI로 구현하는 JWT를 이용한 사용자 로그인 시스템

이번 블로그 포스트에서는 FastAPI 프레임워크를 사용하여 JWT를 이용한 사용자 로그인 시스템을 구현하는 방법에 대해 알아보겠습니다.

FastAPI란?

FastAPI는 파이썬을 기반으로한 현대적이고 빠른 웹 프레임워크입니다. 이 프레임워크는 PydanticType Hints라는 기능을 통해 정적 타입 검사를 지원하며, 간편한 API 문서 생성을 제공합니다.

JWT란?

JWT(JSON Web Tokens)는 인증 정보를 안전하게 전송하기 위해 사용되는 토큰 기반 인증 시스템입니다. 이 토큰은 클라이언트와 서버간의 인증에 사용되며, 정보를 JSON 형태로 암호화하여 전송합니다.

설치

먼저 FastAPI와 JWT를 설치해야 합니다. 아래 명령어를 사용해 필요한 패키지를 설치해주세요.

pip install fastapi
pip install uvicorn
pip install python-jose

구현

먼저, FastAPI 앱을 생성하고 필요한 의존성을 추가해야 합니다. 아래와 같이 코드를 작성해주세요.

from fastapi import FastAPI, HTTPException, Depends
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from passlib.context import CryptContext
from datetime import datetime, timedelta
import jwt

app = FastAPI()

# 비밀 키 설정
SECRET_KEY = "your-secret-key-goes-here"
# 토큰 만료 기간 설정
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# 패스워드 암호화 및 확인을 위한 클래스
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# 사용자 정보
users = [
    {"username": "user1", "hashed_password": "$2b$12$P0B7zNaNlPMpRNB9SwZuIuRS2wkJP..."}
]

# 토큰 생성 함수
def create_access_token(username: str):
    # 초 단위로 만료 시간 계산
    expire = datetime.utcnow() + timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode = {"exp": expire, "username": username}
    # JWT 토큰 생성
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm="HS256")
    return encoded_jwt

# 토큰 검증 함수
def get_current_user(token: str = Depends(oauth2_scheme)):
    try:
        # 토큰 복호화
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
        # 복호화 된 페이로드에서 사용자명 가져오기
        username = payload.get("username")
        if username is None:
            raise HTTPException(status_code=401, detail="Invalid authentication credentials")
    except JWTError:
        raise HTTPException(status_code=401, detail="Invalid authentication credentials")
    return username

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/login")

# 로그인 엔드포인트
@app.post("/login")
def login(form_data: OAuth2PasswordRequestForm = Depends()):
    # 등록된 사용자 확인
    user = None
    for u in users:
        if u["username"] == form_data.username:
            user = u
            break
    if user is None:
        raise HTTPException(status_code=401, detail="Invalid username or password")
    
    # 패스워드 확인
    if not pwd_context.verify(form_data.password, user["hashed_password"]):
        raise HTTPException(status_code=401, detail="Invalid username or password")
    
    # 토큰 생성 및 반환
    access_token = create_access_token(user["username"])
    return {"access_token": access_token, "token_type": "bearer"}

# 보호된 엔드포인트
@app.get("/protected")
def protected(current_user: str = Depends(get_current_user)):
    return {"message": f"Hello, {current_user}!"}

실행

이제 앱을 실행할 차례입니다. 아래 명령어를 사용하여 FastAPI 서버를 실행해주세요.

uvicorn main:app

테스트

이제 로그인 및 보호된 엔드포인트에 대한 테스트를 할 수 있습니다. 아래 예시를 참고해주세요.

로그인

요청:

curl -X POST "http://localhost:8000/login" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -d "username=user1&password=testpassword"

응답:

{"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MzA5MzU4NzM...","token_type":"bearer"}

보호된 엔드포인트

요청:

curl -X GET "http://localhost:8000/protected" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJleHAiOjE2MzA5MzU4NzM...'"

응답:

{"message":"Hello, user1!"}

결론

이렇게 FastAPI와 JWT를 사용하여 사용자 로그인 시스템을 구현하는 방법에 대해 알아보았습니다. JWT는 간단하면서도 안전한 인증 시스템을 제공하기 때문에 많은 프로젝트에서 사용되고 있습니다. FastAPI를 통해 쉽게 구현할 수 있으니, 이를 활용하여 안전하고 신뢰할 수 있는 웹 애플리케이션을 개발해보세요!

#JWT #FastAPI