FastAPI 서버개발, 로그인 라우트 변경

작성일: 2023년 10월 1일

소개

FastAPI는 현대의 웹 API를 빠르고 쉽게 개발할 수 있게 해주는 파워풀한 프레임워크입니다.
Python 3.6 이상을 지원하며, 자동 문서 생성, 데이터 검증, 비동기 프로그래밍 등 다양한 기능을 제공합니다.
이번 글에서는 FastAPI를 이용해 로그인 API를 만들고, 이후에 이를 변경하는 방법에 대해 상세히 설명하겠습니다.
우리는 기본적인 사용자 인증 로직을 구현한 후, 이를 안전하게 변경하는 방법에 대해 단계별로 살펴보겠습니다.

FastAPI 시작하기

FastAPI를 설치하기 위해서는 Python이 설치되어 있어야 합니다. 아래의 명령어를 터미널에 입력하여 FastAPI와 Uvicorn을 설치할 수 있습니다:

pip install fastapi uvicorn

설치가 완료되면, 아래와 같이 기본적인 FastAPI 애플리케이션을 생성할 수 있습니다:

from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def read_root():
    return {"Hello": "World"}

이 코드를 main.py라는 파일에 저장하고, 아래의 명령어를 통해 서버를 실행해볼 수 있습니다:

uvicorn main:app --reload

로그인 라우트 구현하기

이제 사용자가 이메일과 비밀번호를 통해 로그인할 수 있는 API 라우트를 구현해보겠습니다. 먼저, 사용자 정보를 저장하기 위한 간단한 데이터 모델을 만들어야 합니다.

from pydantic import BaseModel

class User(BaseModel):
    email: str
    password: str

다음으로, 로그인 API를 추가합니다:

@app.post("/login")
async def login(user: User):
    # 일반적으로 데이터베이스와의 상호작용이 필요합니다.
    fake_db = {"user@example.com": "hashed_password"}
    
    if user.email in fake_db and user.password == fake_db[user.email]:
        return {"message": "로그인 성공!"}
    return {"message": "잘못된 이메일 또는 비밀번호입니다."}

위 코드는 기본적인 로그인 검증을 수행하고, 성공 여부에 따라 다른 메시지를 반환합니다.

보안 강화

로그인 API의 보안을 강화하기 위해 비밀번호를 해싱하여 저장하면 사용자 정보를 보다 안전하게 보호할 수 있습니다. 비밀번호 해싱에는 bcrypt 라이브러리를 사용할 수 있습니다. 아래를 통해 설치합니다:

pip install bcrypt

그리고 아래와 같이 비밀번호를 해싱하고 확인하는 함수를 구현합니다:

import bcrypt

def hash_password(password: str) -> str:
    return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')

def verify_password(plain_password: str, hashed_password: str) -> bool:
    return bcrypt.checkpw(plain_password.encode('utf-8'), hashed_password.encode('utf-8'))

로그인 라우트에서는 이제 해시된 비밀번호를 사용하여 비밀번호 확인을 수행합니다:

@app.post("/login")
async def login(user: User):
    fake_db = {"user@example.com": hash_password("securepassword")}
    
    if user.email in fake_db and verify_password(user.password, fake_db[user.email]):
        return {"message": "로그인 성공!"}
    return {"message": "잘못된 이메일 또는 비밀번호입니다."}

라우트 변경하기

이제 로그인 라우트를 변경하는 방법을 설명하겠습니다. 예를 들어, 사용자 인증을 JWT(JSON Web Token)를 통해 처리하도록 변경할 수 있습니다. JWT는 클라이언트와 서버 간의 안전한 통신을 가능하게 해주는 토큰 기반 인증 시스템입니다.

우선, 필요한 라이브러리인 pyjwt를 설치합니다:

pip install pyjwt

JWT 토큰을 생성하고 검증하는 유틸리티 함수를 만듭니다:

import jwt
from datetime import datetime, timedelta

SECRET_KEY = "your_secret_key"  # 안전하게 보관해야 합니다.
ALGORITHM = "HS256"

def create_access_token(data: dict, expires_delta: timedelta = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=15)
    to_encode.update({"exp": expire})
    return jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)

def verify_token(token: str):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return payload
    except jwt.PyJWTError:
        return None

이제 로그인 라우트를 변경하여 JWT를 반환하도록 하겠습니다:

@app.post("/login")
async def login(user: User):
    fake_db = {"user@example.com": hash_password("securepassword")}
    
    if user.email in fake_db and verify_password(user.password, fake_db[user.email]):
        access_token = create_access_token(data={"sub": user.email})
        return {"access_token": access_token, "token_type": "bearer"}
    return {"message": "잘못된 이메일 또는 비밀번호입니다."}

토큰 인증을 위한 보호 라우트

이제 JWT를 사용한 보호 라우트를 추가해보겠습니다. 사용자가 로그인 후 발급받은 토큰을 통해 접근할 수 있는 API 엔드포인트를 만들어볼 것입니다.

from fastapi import Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

async def get_current_user(token: str = Depends(oauth2_scheme)):
    payload = verify_token(token)
    if payload is None:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="유효하지 않은 토큰입니다.",
            headers={"WWW-Authenticate": "Bearer"},
        )
    return payload

@app.get("/users/me")
async def read_users_me(current_user: dict = Depends(get_current_user)):
    return current_user

위 코드는 사용자가 JWT를 통해 인증된 경우에만 사용자 정보를 반환하는 방법을 보여줍니다.

결론 및 요약

이 글에서는 FastAPI를 이용하여 로그인 API를 구현하고, 이를 JWT를 통해 변경하는 방법을 단계별로 설명했습니다. 보안이 중요한 현대의 웹 애플리케이션에서 사용자 인증은 필수적이며, FastAPI는 이를 간편하게 처리할 수 있는 다양한 기능을 제공합니다. 다음 단계로는 데이터베이스와의 연동, 사용자 등록 등의 기능을 추가하여 보다 복잡한 시스템을 구축하는 것일 수 있습니다.

FastAPI는 직관적이고 강력한 API 개발을 가능하게 하며, 다양한 라이브러리와의 통합으로 이를 더욱 확장할 수 있습니다. 이 글을 통해 FastAPI의 기능과 JWT를 활용한 인증 방법에 대한 이해가 깊어지기를 바랍니다.