FastAPI에서 세션 관리와 로그인, 로그아웃 기능은 주로 쿠키JWT(JSON Web Tokens) 또는 OAuth2를 사용하여 구현할 수 있습니다. 세션 관리는 서버에 상태를 저장하는 전통적인 방식과, 상태를 저장하지 않고 토큰을 사용하는 방법으로 나뉩니다. 여기서는 JWT 기반의 로그인/로그아웃세션 기반의 로그인/로그아웃 방법을 설명하겠습니다.

1. FastAPI에서 JWT 기반 로그인/로그아웃 구현

JWT는 서버에 세션 정보를 저장하지 않고도 인증할 수 있는 방식을 제공하며, 각 요청마다 JWT를 사용하여 인증합니다. 이를 통해 애플리케이션은 무상태(stateless)로 유지될 수 있습니다.

JWT 설정 및 구현

필요한 라이브러리 설치

FastAPI와 JWT를 사용하기 위해 필요한 라이브러리를 설치합니다.

pip install fastapi[all] pyjwt passlib

JWT 토큰 생성 및 검증을 위한 설정

FastAPI에서 JWT를 생성하고 검증하는 예제를 살펴보겠습니다.

from fastapi import FastAPI, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from pydantic import BaseModel
from datetime import datetime, timedelta
from typing import Optional
import jwt
from passlib.context import CryptContext

# 앱 생성
app = FastAPI()

# 보안 설정
SECRET_KEY = "mysecretkey"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# 유저 데이터 예시
fake_users_db = {
    "testuser": {
        "username": "testuser",
        "full_name": "Test User",
        "email": "test@example.com",
        "hashed_password": "$2b$12$KIXdFh6fDF/hjEPGzTj6me2VVd./tFMyOP58/GKse4Gzi8TOSwlxu", # "password"의 해시값
    }
}

# 비밀번호 해싱 도구 설정
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

# OAuth2를 사용한 비밀번호 기반 인증
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

# 유저 모델 정의
class User(BaseModel):
    username: str
    email: Optional[str] = None
    full_name: Optional[str] = None

class UserInDB(User):
    hashed_password: str

class Token(BaseModel):
    access_token: str
    token_type: str

def verify_password(plain_password, hashed_password):
    return pwd_context.verify(plain_password, hashed_password)

def get_password_hash(password):
    return pwd_context.hash(password)

def get_user(db, username: str):
    if username in db:
        user_dict = db[username]
        return UserInDB(**user_dict)

def authenticate_user(fake_db, username: str, password: str):
    user = get_user(fake_db, username)
    if not user or not verify_password(password, user.hashed_password):
        return False
    return user

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

@app.post("/token", response_model=Token)
async def login(form_data: OAuth2PasswordRequestForm = Depends()):
    user = authenticate_user(fake_users_db, form_data.username, form_data.password)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid username or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token = create_access_token(data={"sub": user.username}, expires_delta=timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES))
    return {"access_token": access_token, "token_type": "bearer"}

@app.get("/users/me", response_model=User)
async def read_users_me(token: str = Depends(oauth2_scheme)):
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        username: str = payload.get("sub")
        if username is None:
            raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials")
        token_data = {"username": username}
    except jwt.PyJWTError:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Could not validate credentials")

    user = get_user(fake_users_db, username=token_data["username"])
    if user is None:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="User not found")
    return user

코드 설명

  • login 엔드포인트는 사용자의 자격 증명을 검증하고 JWT를 발급합니다.
  • read_users_me 엔드포인트는 발급된 JWT를 통해 사용자를 인증합니다. JWT가 유효하지 않으면 401 Unauthorized 응답을 반환합니다.
  • JWT 토큰은 sub 필드에 사용자의 이름을 포함하고, 만료 시간을 설정할 수 있습니다.

실행 및 테스트

서버 실행 후 /token 엔드포인트에 POST 요청을 보내어 access_token을 받습니다. 이 토큰을 /users/me 엔드포인트의 Authorization 헤더에 Bearer 타입으로 포함하여 요청하면 사용자 정보를 확인할 수 있습니다.


2. FastAPI에서 쿠키 기반 세션 관리 및 로그인/로그아웃 구현

세션 기반 인증은 보통 쿠키를 사용하여 세션 정보를 관리하며, 사용자 정보를 서버에 저장하여 관리합니다. 다음은 간단한 세션 기반 로그인/로그아웃 예제입니다.

FastAPI에서 세션 관리 예제

세션 관리를 위해 starlette.middleware.sessions를 사용하여 세션 미들웨어를 추가합니다.

필요한 라이브러리 설치

pip install fastapi[all]

세션을 이용한 로그인 구현

from fastapi import FastAPI, Request, Depends, Form, HTTPException
from fastapi.responses import RedirectResponse
from fastapi.middleware.sessions import SessionMiddleware
from starlette.responses import JSONResponse

# FastAPI 앱 생성 및 세션 미들웨어 추가
app = FastAPI()
app.add_middleware(SessionMiddleware, secret_key="mysecretkey")

# 유저 데이터베이스 예시
fake_users_db = {
    "testuser": {
        "username": "testuser",
        "password": "password"
    }
}

def authenticate_user(username: str, password: str):
    user = fake_users_db.get(username)
    return user and user["password"] == password

@app.post("/login")
async def login(request: Request, username: str = Form(...), password: str = Form(...)):
    if authenticate_user(username, password):
        request.session["username"] = username
        return JSONResponse(content={"message": "Login successful"})
    else:
        raise HTTPException(status_code=400, detail="Invalid credentials")

@app.get("/logout")
async def logout(request: Request):
    request.session.clear()
    return JSONResponse(content={"message": "Logout successful"})

@app.get("/profile")
async def profile(request: Request):
    username = request.session.get("username")
    if not username:
        raise HTTPException(status_code=401, detail="Not authenticated")
    return {"username": username}

코드 설명

  • SessionMiddleware: 쿠키 기반 세션을 위해 SessionMiddleware를 FastAPI 애플리케이션에 추가합니다.
  • login 엔드포인트: 로그인 자격을 확인하고, 세션에 사용자 정보를 저장합니다.
  • logout 엔드포인트: 세션을 삭제하여 사용자를 로그아웃합니다.
  • profile 엔드포인트: 세션에 저장된 사용자 정보를 확인합니다. 인증되지 않은 사용자는 401 Unauthorized 응답을 받습니다.

실행 및 테스트

로그인 후 /profile 엔드포인트를 호출하면 세션에 저장된 사용자 정보를 확인할 수 있습니다. 로그아웃 요청 후 /profile을 다시 호출하면 인증되지 않은 상태로 간주됩니다.

결론

FastAPI에서 JWT와 세션 기반 로그인/로그아웃을 설정하는 방법을 살펴보았습니다. FastAPI는 다양한 인증 방식을 지원하며, RESTful API 및 인증 시스템을 효율적으로 구현할 수 있습니다.

FastAPI는 파이썬에서 사용되는 고성능 마이크로 웹 프레임워크로, 주로 RESTful API를 빠르고 쉽게 만들기 위해 설계되었습니다. FastAPI는 속도와 생산성, 자동 문서화, 타입 안전성을 강조하며, 최신 파이썬 기능(특히 타이핑 기능)을 활용하는 것이 특징입니다. 이 프레임워크는 ASGI(Asynchronous Server Gateway Interface)를 기반으로 비동기 처리를 지원하며, 비동기 웹 애플리케이션 개발에 최적화되어 있습니다.

아래에서는 FastAPI의 특징, 구조, 그리고 예제 코드를 통해 어떻게 활용할 수 있는지 설명하겠습니다.

1. FastAPI의 주요 특징

1.1. 빠른 성능

  • StarlettePydantic 라이브러리를 기반으로 구축되어, 비동기적 처리를 지원함으로써 매우 빠른 속도를 자랑합니다.
  • 성능 면에서 FastAPI는 Node.js, Go와 비슷한 수준으로 평가받고 있습니다.

1.2. 타입 힌트 기반

  • FastAPI는 파이썬의 타입 힌트를 적극적으로 사용하여 코드를 작성할 때 자동으로 데이터 검증, 변환 및 문서화를 지원합니다. 이를 통해 더 안전하고 명확한 코드를 작성할 수 있습니다.
  • 타입 힌트를 기반으로 API 입력 값의 유효성을 검사하고, 자동으로 Swagger 및 ReDoc을 통해 API 문서를 생성합니다.

1.3. 자동 API 문서화

  • FastAPI는 기본적으로 Swagger UIReDoc을 사용하여 자동으로 API 문서를 생성합니다. 이를 통해 API를 쉽게 테스트하고 문서화할 수 있습니다.

1.4. 비동기 지원

  • FastAPI는 기본적으로 비동기 함수(async)를 지원합니다. 이를 통해 I/O가 많은 작업(예: 데이터베이스 접근, 외부 API 호출 등)에서 성능을 극대화할 수 있습니다.

1.5. 쉬운 데이터 검증

  • Pydantic을 사용하여 데이터 검증 및 변환을 간단하게 처리할 수 있습니다. FastAPI는 Pydantic 모델을 활용하여 요청과 응답 데이터를 쉽게 정의할 수 있습니다.

2. FastAPI의 구조

FastAPI는 다음과 같은 요소들로 구성됩니다:

  • 엔드포인트 정의: FastAPI는 @app.get(), @app.post() 등의 데코레이터를 사용하여 간단하게 API 엔드포인트를 정의합니다.
  • 비동기 함수 지원: 비동기 처리를 위해 async 키워드를 사용하며, 비동기 함수에서 I/O를 효율적으로 처리합니다.
  • 경로 매개변수: 경로에 포함된 변수들을 함수의 매개변수로 쉽게 처리할 수 있습니다.
  • 쿼리 매개변수 및 요청 본문 처리: 요청에서 쿼리 파라미터 및 JSON 본문을 자동으로 매핑하고 검증합니다.
  • 응답 모델: API 응답 데이터를 Pydantic 모델로 정의하여, 명시적인 데이터 구조를 가집니다.

3. FastAPI 설치 및 예제 코드

3.1. FastAPI 설치

FastAPI는 다음 명령어로 설치할 수 있습니다:

pip install fastapi
pip install "uvicorn[standard]"

uvicorn은 FastAPI 애플리케이션을 실행하기 위한 ASGI 서버입니다.

3.2. 간단한 FastAPI 예제

아래는 기본적인 FastAPI 애플리케이션을 구현한 예제입니다.

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

# 요청 본문에 대한 모델 정의
class Item(BaseModel):
    name: str
    description: str = None
    price: float
    tax: float = None

# 루트 엔드포인트
@app.get("/")
async def read_root():
    return {"message": "Hello, FastAPI"}

# 경로 매개변수
@app.get("/items/{item_id}")
async def read_item(item_id: int, q: str = None):
    return {"item_id": item_id, "q": q}

# POST 요청 처리
@app.post("/items/")
async def create_item(item: Item):
    return {"name": item.name, "price": item.price}

3.3. FastAPI 애플리케이션 실행

FastAPI 애플리케이션을 실행하려면 다음 명령어를 터미널에서 실행합니다:

uvicorn main:app --reload
  • main:appmain.py 파일에 정의된 app 객체를 참조한다는 의미입니다.
  • --reload 옵션은 코드가 변경될 때마다 서버를 자동으로 다시 시작하도록 합니다.

3.4. FastAPI 자동 문서화

애플리케이션이 실행된 후 브라우저에서 다음 URL로 접근하여 자동으로 생성된 API 문서를 확인할 수 있습니다:

  • Swagger UI: http://127.0.0.1:8000/docs
  • ReDoc: http://127.0.0.1:8000/redoc

이 문서는 FastAPI가 제공하는 데이터와 엔드포인트를 쉽게 확인하고 테스트할 수 있는 인터페이스를 제공합니다.

4. FastAPI의 주요 기능

4.1. 경로 매개변수

FastAPI는 경로 내에서 변수 값을 쉽게 처리할 수 있습니다. 예를 들어, 경로 /items/{item_id}item_id라는 경로 매개변수를 전달받을 수 있습니다.

4.2. 쿼리 매개변수

쿼리 매개변수는 URL의 ? 뒤에 나오는 값을 처리하는 데 사용됩니다. 예를 들어, /items/{item_id}?q=somequery에서 q는 쿼리 매개변수입니다.

4.3. 요청 본문 처리

POST 요청에서 JSON 형태의 데이터를 받기 위해서는 Pydantic 모델을 정의하고, 이를 통해 데이터를 자동으로 검증하고 변환할 수 있습니다.

4.4. 응답 모델

FastAPI는 응답 데이터 구조를 명시적으로 정의할 수 있습니다. 이를 통해 API 응답 데이터를 명확하게 관리하고 문서화할 수 있습니다.

5. FastAPI의 응용

FastAPI는 간단한 REST API부터 대규모 백엔드 서비스까지 다양한 용도로 활용될 수 있습니다. 특히 비동기 처리를 지원하여, 성능이 중요한 애플리케이션(예: 실시간 서비스, API 게이트웨이 등)에 적합합니다.

  • 대규모 웹 서비스: FastAPI는 확장성과 속도를 고려하여 설계되었기 때문에, 고성능 API 서버나 마이크로서비스 아키텍처를 구축하는 데 적합합니다.
  • 데이터 검증 및 API 문서화: 자동으로 생성되는 API 문서와 데이터 검증 기능 덕분에, 다양한 데이터 처리 애플리케이션에서도 편리하게 사용할 수 있습니다.

결론

FastAPI는 빠른 개발 속도와 고성능을 제공하는 파이썬 기반의 웹 프레임워크로, 최신 파이썬 기능을 적극적으로 활용하여 API 개발을 효율적으로 수행할 수 있도록 도와줍니다. 또한 자동화된 문서화와 쉬운 데이터 검증 기능을 통해 개발자의 생산성을 극대화할 수 있습니다.

+ Recent posts