FastAPI 서버개발, 액세스 토큰 생성과 검증

작성자: 조광형

날짜: 2024년 11월 26일

1. 서론

FastAPI는 Python을 기반으로 하는 현대적인 웹 프레임워크로, 비동기 프로그래밍을 지원하며 최적화된 성능을 자랑합니다. RESTful API를 쉽게 구축할 수 있도록 돕는 FastAPI의 특징 중 하나는 데이터 검증과 자동 문서 생성 기능입니다. 이 강좌에서는 FastAPI를 사용하여 액세스 토큰을 생성하고 검증하는 방법에 대해 다룹니다. 액세스 토큰은 인증 및 권한 부여에 필수적이며, 깔끔하고 안전한 API를 만드는 데 중요한 요소입니다.

2. FastAPI 기본 설정

FastAPI를 사용하기 위해 먼저 필요한 라이브러리를 설치해야 합니다. 아래 명령어를 통해 FastAPI와 필요한 종속성을 설치합니다.

pip install fastapi[all] python-jose

다음으로 FastAPI 애플리케이션을 생성합니다. 아래의 코드는 가장 기본적인 FastAPI 서버를 설정하는 방법을 보여줍니다.


from fastapi import FastAPI

app = FastAPI()

@app.get("/")
async def root():
    return {"message": "Hello, FastAPI!"}
            

위 코드를 실행한 후 웹 브라우저에서 http://localhost:8000에 접속하면 “Hello, FastAPI!”라는 메시지를 확인할 수 있습니다.

3. JWT(Json Web Token) 이해하기

액세스 토큰을 구현하기 위해서는 JWT를 사용합니다. JWT는 클라이언트와 서버 간의 안전한 정보를 전달하기 위한 표준으로, 세 부분으로 구성됩니다: 헤더, 페이로드, 서명. 이를 통해 데이터를 안전하게 전송할 수 있습니다.

  • 헤더: 토큰의 타입과 사용되는 알고리즘을 정의합니다.
  • 페이로드: 전달할 정보를 포함합니다. 예를 들어, 사용자 ID, 만료 시간 등의 정보를 담을 수 있습니다.
  • 서명: 헤더와 페이로드를 비밀키로 해시하여 생성된 값으로, 데이터의 무결성을 확인하는 데 사용됩니다.

4. 액세스 토큰 생성 및 검증 구현하기

이제 액세스 토큰을 생성하고 검증하는 작업을 진행해 보겠습니다. 이를 위해 Python의 python-jose 라이브러리를 사용할 것입니다. 먼저, 토큰을 생성하는 함수를 만들어 보겠습니다.


from datetime import datetime, timedelta
from jose import JWTError, jwt
from fastapi import Depends, HTTPException, status, Security
from fastapi.security import OAuth2PasswordBearer
from typing import Optional

SECRET_KEY = "mysecretkey"  # 비밀키
ALGORITHM = "HS256"  # 알고리즘
ACCESS_TOKEN_EXPIRE_MINUTES = 30  # 만료 시간 설정

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

def create_access_token(data: dict, expires_delta: Optional[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})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt
            

위 코드는 액세스 토큰을 생성하는 함수입니다. 사용자가 로그인 할 때 이 함수를 호출하여 액세스 토큰을 생성합니다.

5. 액세스 토큰을 사용하는 사용자 인증

다음으로 사용자 인증을 위한 엔드포인트를 만들어 보겠습니다. 사용자 로그인을 처리하고, 액세스 토큰을 반환하는 API 를 작성합니다.


from pydantic import BaseModel

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

fake_users_db = {
    "testuser": {
        "username": "testuser",
        "full_name": "Test User",
        "email": "testuser@example.com",
        "hashed_password": "fakehashedpassword",
        "disabled": False,
    }
}

def fake_hash_password(password: str):
    return "fakehashed" + password

@app.post("/token")
async def login(user: User):
    user_dict = fake_users_db.get(user.username)
    if not user_dict or user_dict["hashed_password"] != fake_hash_password(user.password):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(data={"sub": user.username}, expires_delta=access_token_expires)
    return {"access_token": access_token, "token_type": "bearer"}
            

위 코드는 로그인을 처리하고 액세스 토큰을 반환하는 /token 엔드포인트입니다. 사용자가 올바른 사용자 이름과 비밀번호를 제공하면, 액세스 토큰이 생성되어 반환됩니다.

6. 토큰 검증

액세스 토큰이 생성되면, 이를 검증하는 것이 중요합니다. 특정 엔드포인트에 액세스하기 위해서는 유효한 토큰이 필요합니다. 아래 코드를 통해 이를 구현할 수 있습니다.


async def get_current_user(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Could not validate credentials",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise credentials_exception
    except JWTError:
        raise credentials_exception
    user = fake_users_db.get(username)
    if user is None:
        raise credentials_exception
    return user

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

위의 코드는 액세스 토큰을 검증하고 해당 사용자 정보를 반환하는 /users/me 엔드포인트입니다. 요청에서 토큰을 추출하여 사용자 정보를 확인합니다.

7. 테스트

API를 테스트하기 위해, curl이나 Postman과 같은 도구를 사용할 수 있습니다. 아래는 Postman에서의 테스트 방법입니다:

  1. POST 요청을 통해 사용자 로그인:

    POST http://localhost:8000/token

    Body에 JSON 형태로 사용자 이름과 비밀번호를 입력합니다:

    {"username": "testuser", "password": "testpassword"}
  2. 응답으로 받은 액세스 토큰을 이용하여 사용자 정보 요청:

    GET http://localhost:8000/users/me

    Authorization 헤더에 Bearer {access_token}을 추가합니다.

8. 결론

이번 강좌에서는 FastAPI를 사용하여 액세스 토큰을 생성하고 검증하는 방법에 대해 학습했습니다. FastAPI의 강력한 기능은 다양한 인증 방법을 구현하는 데 유용합니다. JWT를 통한 인증은 API의 보안을 강화하는 중요한 방법 중 하나입니다.

추가적인 개선 사항으로는 사용자 데이터베이스 통합, 비밀번호 해싱 강화, 그리고 에러 처리 로직을 추가할 수 있습니다.

이 글이 FastAPI를 통한 API 개발에 도움이 되었기를 바랍니다.