FastAPI 서버개발, WebSocket을 이용한 실시간 통신 구현

FastAPI는 현대적인 웹 API를 쉽게 구축할 수 있도록 설계된 파이썬 웹 프레임워크입니다. RESTful API뿐만 아니라 WebSocket을 이용한 실시간 통신 기능을 지원하는데, 이를 통해 클라이언트와 서버 간의 양방향 통신이 가능해집니다. 이번 글에서는 FastAPI를 사용하여 WebSocket을 통한 실시간 통신을 구현하는 방법에 대해 자세히 알아보겠습니다.

1. FastAPI 개요

FastAPI는 고성능 웹 서버를 구축하는 데 매우 효율적이며, 다음과 같은 주요 기능을 제공합니다.

  • 비동기 프로그래밍 지원: 비동기 처리를 통해 더 많은 요청을 동시에 처리할 수 있습니다.
  • 자동 문서화: Swagger UI와 ReDoc을 통해 자동으로 API 문서를 생성합니다.
  • Python 타입 힌트 활용: 타입 힌트를 통해 코드의 가독성과 유지보수성을 높입니다.

2. WebSocket이란?

WebSocket은 클라이언트와 서버 간의 전이중(Full-Duplex) 통신을 가능하게 하는 프로토콜입니다. HTTP와는 다르게, WebSocket을 사용하면 클라이언트가 서버에 요청하지 않고도 서버로부터 실시간 업데이트를 받을 수 있습니다. 이로 인해 채팅 응용 프로그램, 실시간 데이터 피드 등과 같은 다양한 애플리케이션에 적합합니다.

3. FastAPI 설치하기

FastAPI를 사용하려면 먼저 FastAPI와 ASGI 서버(Uvicorn)를 설치해야 합니다. 다음 명령어를 사용하여 설치할 수 있습니다:

pip install fastapi uvicorn

4. FastAPI WebSocket 예제

이제 FastAPI를 사용하여 간단한 WebSocket 서버를 구현해 보겠습니다. 이 예제에서는 클라이언트가 서버에 연결하고 메시지를 주고받는 기본적인 기능을 구현하겠습니다.

4.1 기본 WebSocket 서버 만들기

from fastapi import FastAPI, WebSocket
from fastapi.responses import HTMLResponse

app = FastAPI()

html = """




    
    
    WebSocket Chat


    

WebSocket Chat


""" @app.get("/") async def get(): return HTMLResponse(html) @app.websocket("/ws") async def websocket_endpoint(websocket: WebSocket): await websocket.accept() while True: data = await websocket.receive_text() await websocket.send_text(f"메시지 수신: {data}")

4.2 코드 설명

위 코드는 FastAPI를 사용하여 WebSocket 서버를 구현한 것입니다.

  • FastAPI 모듈에서 FastAPIWebSocket를 가져옵니다.
  • html 변수에 클라이언트 측 HTML 코드를 저장합니다. 클라이언트는 이 HTML 코드를 통해 WebSocket 서버에 연결하고 메시지를 주고받을 수 있습니다.
  • get() 함수는 클라이언트의 GET 요청에 대해 HTML 페이지를 반환합니다.
  • websocket_endpoint() 함수는 WebSocket 요청을 처리합니다. 클라이언트가 연결할 때 await websocket.accept()로 연결을 승인하고, 이후 클라이언트로부터 메시지를 받으면 확인 메시지를 다시 전송합니다.

5. 웹소켓 서버 실행하기

서버 코드를 작성한 후, 다음 명령어로 FastAPI 서버를 실행합니다:

uvicorn main:app --reload

이 명령어에서 main은 Python 파일의 이름이고, app는 FastAPI 인스턴스입니다.

6. WebSocket 클라이언트 테스트하기

브라우저에서 http://localhost:8000를 방문하면 웹소켓 채팅 인터페이스가 나타납니다. 메시지를 입력한 후 “전송” 버튼을 누르면, 서버에서 수신한 메시지가 다시 클라이언트로 전송되고, 텍스트 영역에 표시됩니다.

7. WebSocket의 고급 기능 구현하기

이제 기본적인 WebSocket 구현에 대해 알아보았으므로, 다음 단계로는 여러 클라이언트가 동시에 연결하여 서로 메시지를 주고받을 수 있는 기능을 추가하겠습니다. 이를 위해 클라이언트 관리를 위한 리스트와 메시지 방송 기능을 구현하겠습니다.

7.1 여러 클라이언트를 위한 코드 수정

from fastapi import FastAPI, WebSocket
from fastapi.responses import HTMLResponse
from typing import List

app = FastAPI()
clients: List[WebSocket] = []

html = """




    
    
    WebSocket Chat


    

WebSocket Chat


""" @app.get("/") async def get(): return HTMLResponse(html) @app.websocket("/ws") async def websocket_endpoint(websocket: WebSocket): await websocket.accept() clients.append(websocket) try: while True: data = await websocket.receive_text() for client in clients: if client != websocket: # 현재 클라이언트를 제외하고 메시지 전송 await client.send_text(f"전달된 메시지: {data}") except Exception as e: print("클라이언트가 연결을 종료했습니다.", e) finally: clients.remove(websocket)

7.2 추가된 기능 설명

위 코드에서는 클라이언트를 관리하는 clients 리스트를 추가하여 현재 연결된 모든 클라이언트를 저장합니다. 메시지를 수신하면, 모든 클라이언트에게 그 메시지를 전송하여 서로 간의 채팅이 가능하도록 합니다. 다음은 코드의 주요 변경 사항입니다:

  • 클라이언트가 연결될 때 clients 리스트에 추가합니다.
  • 서버는 모든 클라이언트에게 수신한 메시지를 전송하고, 현재 클라이언트를 제외합니다.
  • 예외가 발생할 경우(예: 클라이언트 연결 종료) finally 블록에서 해당 클라이언트를 리스트에서 제거합니다.

8. 클라이언트 어플리케이션 만들기

지금까지의 설명을 통해 간단한 WebSocket 서버를 구현했습니다. 이제는 위의 예제를 바탕으로 프론트엔드와 백엔드를 통합한 클라이언트 어플리케이션을 만들어보겠습니다. React, Vue.js, 또는 Angular와 같은 프론트엔드 프레임워크를 사용할 수 있습니다.

8.1 React를 통한 WebSocket 클라이언트 구현하기

React를 사용하여 WebSocket 클라이언트를 만들어보겠습니다.

import React, { useState, useEffect } from 'react';

function App() {
    const [socket, setSocket] = useState(null);
    const [message, setMessage] = useState('');
    const [chat, setChat] = useState([]);

    useEffect(() => {
        const ws = new WebSocket('ws://localhost:8000/ws');
        ws.onmessage = (event) => {
            setChat((prevChat) => [...prevChat, event.data]);
        };
        setSocket(ws);

        return () => {
            ws.close();
        };
    }, []);

    const sendMessage = () => {
        if (socket) {
            socket.send(message);
            setMessage('');
        }
    };

    return (
        

WebSocket Chat


setMessage(e.target.value)} placeholder="메시지를 입력하세요..." />
); } export default App;

9. 결론

이번 포스트를 통해 FastAPI를 사용하여 WebSocket을 통한 실시간 통신을 구현하는 방법에 대해 알아보았습니다. FastAPI의 장점을 살리면서, 비동기 방식으로 클라이언트와 서버 간의 실시간 소통을 구현할 수 있었습니다. 이러한 기술은 다양한 응용 분야에 활용될 수 있으며, 실시간 데이터 처리와 자극적인 UX를 제공하는 데 기여할 것입니다.

10. 참고 자료

FastAPI 서버개발, 컨테이너 이미지 업로드 ECR 이용하기

최근 들어 마이크로서비스 아키텍처가 인기를 끌면서 RESTful API를 이용한 서버 개발이 중요한 기술로 자리잡고 있습니다. FastAPI는 이러한 RESTful API를 쉽게 만들 수 있는 현대적인 웹 프레임워크로, 비동기 처리를 지원하며, 빠르게 성능을 최적화할 수 있는 장점이 있습니다. 본 강좌에서는 FastAPI를 사용하여 백엔드 서버를 개발하고 AWS Elastic Container Registry(ECR)를 이용하여 컨테이너 이미지를 업로드하는 방법을 상세히 설명하겠습니다.

1. FastAPI란?

FastAPI는 Python3.6 이상에서 사용할 수 있는 빠른 웹 프레임워크입니다. 높은 성능과 쉬운 사용법, 데이터 검증, Swagger UI 자동 생성을 제공하여 RESTful API를 효율적으로 구축할 수 있게 도와줍니다.

주요 특징:

  • 비동기 프로그래밍 지원
  • 데이터 유효성 검사 및 직렬화
  • 자동 API 문서화
  • 고성능: Starlette와 Pydantic 기반

2. FastAPI 환경 설정

FastAPI를 사용하기 위해서는 Python이 설치되어 있어야 하며, 다음과 같은 패키지를 설치해야 합니다.

pip install fastapi uvicorn boto3

이후 가장 간단한 FastAPI 애플리케이션을 생성하여 실행해 보겠습니다.

2.1 첫 번째 FastAPI 애플리케이션

from fastapi import FastAPI

app = FastAPI()

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

위 코드를 main.py라는 파일에 저장한 후, 서버를 실행해보세요.

uvicorn main:app --reload

브라우저에서 http://127.0.0.1:8000에 접속하면 “Hello, FastAPI!” 메시지를 확인할 수 있습니다.

3. ECR에 대해 알아보기

AWS Elastic Container Registry(ECR)는 Docker 이미지를 저장하고 관리할 수 있는 완전 관리형 컨테이너 레지스트리 서비스입니다. ECR은 이미지 배포와 버전 관리를 간단하게 할 수 있도록 도와줍니다.

3.1 ECR 설정하기

  1. AWS Management Console에서 ECR 서비스로 이동합니다.
  2. 레지스트리를 생성합니다.
  3. IAM 사용자에게 ECR 권한을 부여합니다.
  4. 레지스트리 URI를 복사합니다.

4. FastAPI 애플리케이션 Dockerize

이제 FastAPI 애플리케이션을 Docker 이미지로 패키징해보겠습니다. Dockerfile을 생성하고 아래와 같이 작성합니다.

FROM tiangolo/uvicorn-gunicorn-fastapi:python3.9

COPY ./main.py /app/main.py

# 설치할 추가 패키지가 있다면 아래에 추가하세요.
RUN pip install -U pip
RUN pip install -U boto3

CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "80"]

4.1 Docker 이미지 빌드하기

Docker 이미지를 빌드하려면 다음 명령어를 사용합니다.

docker build -t fastapi-app .

5. ECR에 Docker 이미지 푸시하기

ECR에 Docker 이미지를 업로드하기 위해서는 먼저 로그인해야 합니다. AWS CLI를 사용하여 인증을 수행할 수 있습니다.

aws ecr get-login-password --region YOUR_REGION | docker login --username AWS --password-stdin YOUR_AWS_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com

이후 ECR에서 컨테이너 이미지를 푸시할 수 있습니다.

docker tag fastapi-app:latest YOUR_AWS_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com/YOUR_REPOSITORY_NAME:latest
docker push YOUR_AWS_ACCOUNT_ID.dkr.ecr.YOUR_REGION.amazonaws.com/YOUR_REPOSITORY_NAME:latest

6. FastAPI와 ECR의 통합

이제 FastAPI로 구축한 백엔드 서버와 AWS ECR을 통한 이미지 업로드가 완료되었습니다. ECR에 푸시한 이미지를 기반으로 AWS 서비스와 통합하여 다양한 어플리케이션을 개발할 수 있습니다.

7. 마무리

이 강좌를 통해 FastAPI를 사용하여 RESTful API 서버를 개발하고, AWS Elastic Container Registry를 통해 Docker 이미지를 업로드하는 방법을 알게 되었습니다. FastAPI의 사용법과 AWS의 다양한 기능을 활용하여 실제로 동작하는 어플리케이션을 구축해 보세요. 추가적인 질문이나 피드백이 있으면 댓글로 남겨주시기 바랍니다. 감사합니다!

FastAPI 서버개발, 실시간 채팅 애플리케이션 개발하기

최근 몇 년간 웹 애플리케이션 개발에서 실시간 통신의 필요성이 증가하면서 WebSocket을 통한 실시간 애플리케이션의 개발이 주목받고 있습니다. FastAPI는 Python으로 만들어진 현대적인 웹 프레임워크로, 고성능 비동기 프로그래밍을 지원하여 실시간 채팅 애플리케이션 개발에 적합합니다. 본 글에서는 FastAPI를 활용하여 실시간 채팅 애플리케이션을 만드는 방법을 단계별로 설명하겠습니다.

1. FastAPI란?

FastAPI는 Python 3.6 이상에서 사용할 수 있는 웹 프레임워크로, RESTful API를 신속하게 구축할 수 있도록 도와줍니다. FastAPI는 다음과 같은 주요 특징이 있습니다:

  • 고속성: Starlette를 기반으로 하고 있어 비동기 프로그래밍이 가능합니다.
  • 자동화된 API 문서화: OpenAPI 스펙을 기반으로 자동화된 Swagger UI와 ReDoc 문서가 생성됩니다.
  • 타입 힌트 지원: Python의 타입 힌트를 활용하여 오류를 사전에 방지하고, 가독성을 높입니다.

2. 개발 환경 설정

실시간 채팅 애플리케이션을 개발하기 위해서 먼저 개발 환경을 설정합니다. Python 3.x가 설치되어 있다고 가정하고, 필요한 패키지를 설치합니다.

pip install fastapi uvicorn websockets

3. FastAPI 애플리케이션 구조

프로젝트 디렉토리를 생성하고 기본 구조를 설정합니다.

mkdir fastapi_chat
cd fastapi_chat
touch main.py

main.py 파일 작성

이제 main.py 파일에 FastAPI 애플리케이션과 WebSocket 핸들러를 작성하겠습니다.

from fastapi import FastAPI, WebSocket, WebSocketDisconnect
from fastapi.responses import HTMLResponse

app = FastAPI()

# HTML 페이지를 반환하는 API
@app.get("/")
async def get():
    return HTMLResponse(content="""
    
        
            Chat Application
        
        
            

Chat Application

""") # WebSocket 핸들러 connections = [] @app.websocket("/ws") async def websocket_endpoint(websocket: WebSocket): await websocket.accept() connections.append(websocket) try: while True: data = await websocket.receive_text() # 연결된 모든 클라이언트에게 메시지를 broadcast for connection in connections: await connection.send_text(data) except WebSocketDisconnect: connections.remove(websocket)

4. 코드 설명

위 코드는 FastAPI를 사용하여 기본적인 웹소켓 서버와 HTML 클라이언트를 구현한 것입니다. 간단히 설명해보겠습니다:

  • FastAPI 인스턴스: 애플리케이션 객체를 생성합니다.
  • HTML 반환: get 함수는 클라이언트에게 HTML 페이지를 반환합니다.
  • WebSocket 핸들러: /ws 엔드포인트는 클라이언트와의 실시간 연결을 관리합니다.
  • 메시지 브로드캐스트: 클라이언트가 서버에 메시지를 보낼 때, 연결된 모든 클라이언트에게 메시지를 전송합니다.

5. 애플리케이션 실행

애플리케이션을 실행하기 위해 터미널에서 다음 명령어를 입력합니다.

uvicorn main:app --reload

이제 브라우저에서 http://localhost:8000에 접속하면 채팅 애플리케이션이 열립니다. 여러 개의 브라우저 탭을 열고 메시지를 보내보세요. 모든 탭에서 메시지가 실시간으로 표시되는 것을 확인할 수 있습니다.

6. 추가 기능 구현

기본적인 채팅 기능 외에도 여러 가지 기능을 추가할 수 있습니다. 예를 들어 사용자 이름, 메시지 이력 저장, 그리고 사용자별로 메시지 필터링 등을 구현할 수 있습니다.

6.1 사용자 이름 기능 추가

사용자가 채팅에 참여할 때 사용자 이름을 입력하게 할 수 있습니다. HTML 코드에 사용자 이름 입력란을 추가하고, 메시지를 전송할 때 이 사용자 이름을 포함시켜 보겠습니다.

HTMLResponse(content="""

    
        Chat Application
    
    
        

Chat Application

""")

6.2 메시지 이력 저장

서버에서 전송된 메시지를 저장하여 사용자가 페이지를 새로고침 해도 이전 메시지를 볼 수 있도록 만들 수 있습니다. 이를 위해 메모리 내 저장소를 사용할 수 있는데, 더 나아가 데이터베이스 연결도 고려할 수 있습니다. 간단하게 메시지 리스트를 추가하고, 클라이언트가 연결할 때 이 메시지를 전송하는 방법을 구현해 보겠습니다.

messages = []

async def broadcast_message(message: str):
    messages.append(message)
    for connection in connections:
        await connection.send_text(message)

@app.websocket("/ws")
async def websocket_endpoint(websocket: WebSocket):
    await websocket.accept()
    connections.append(websocket)
    try:
        # 기존 메시지를 클라이언트에 전송
        for message in messages:
            await websocket.send_text(message)
        while True:
            data = await websocket.receive_text()
            await broadcast_message(data)
    except WebSocketDisconnect:
        connections.remove(websocket)

7. 마무리

이번 글에서는 FastAPI를 사용하여 실시간 채팅 애플리케이션을 개발하는 방법에 대해 알아보았습니다. FastAPI의 비동기 기능을 활용하여 고성능의 실시간 웹 소켓 서버를 구축하고 클라이언트와의 안정적인 연결을 유지하는 법을 배웠습니다.

FastAPI는 강력하면서도 간단한 API 개발 도구로, 다양한 기능들을 확장하여 더욱 복잡한 애플리케이션을 구축할 수 있습니다. 추가적으로 데이터베이스와의 연결, 사용자 인증 및 인가, 그리고 서드파티 API와의 통합 등을 통해 발전시키기 바랍니다.

FastAPI를 통해 여러분의 아이디어를 실현해보세요! 학습과 경험을 통해 더욱 많은 애플리케이션을 개발할 수 있을 것입니다.

감사합니다.

FastAPI 서버개발, OAuth2와 JWT를 사용한 애플리케이션 보안

현대 웹 애플리케이션은 다양한 보안 위협에 노출되어 있으며, 사용자 인증 및 권한 부여는 이러한 위협으로부터 애플리케이션을 보호하는 데 필수적입니다. 본 블로그에서는 FastAPI를 사용하여 OAuth2 프로토콜과 JWT(JSON Web Token)를 통한 인증 및 권한 부여 시스템을 구축하는 방법을 자세히 설명하겠습니다. 이 글을 통해 독자들은 FastAPI로 안전한 애플리케이션을 개발하는 데 필요한 지식을 습득할 수 있을 것입니다.

1. FastAPI 소개

FastAPI는 Python으로 작성된 최신 웹 프레임워크로, 매우 빠르고 현대적인 API를 개발하기 위해 설계되었습니다. FastAPI는 다음과 같은 주요 특징을 가지고 있습니다:

  • 높은 성능: FastAPI는 Starlette를 기반으로 하여 비동기 처리를 최적화하고, Uvicorn 등의 비동기 서버와 함께 사용할 수 있습니다.
  • 자동 문서화: FastAPI는 OpenAPI 및 JSON Schema를 지원하여 문서화를 자동으로 생성할 수 있습니다.
  • 쉬운 사용: 간단한 코드로 복잡한 API를 구축할 수 있습니다.

1.1 FastAPI 설치

FastAPI를 사용하려면 먼저 FastAPI와 Uvicorn을 설치해야 합니다. 다음 명령어를 사용하여 설치할 수 있습니다:

pip install fastapi uvicorn

2. OAuth2와 JWT 개요

OAuth2는 사용자가 제3자 애플리케이션에 대한 접근을 제어할 수 있도록 해주는 권한 부여 프레임워크입니다. JWT는 인증 정보를 안전하게 전송하기 위해 정보의 전자 서명된 JSON 객체입니다. 이 두 기술을 결합하면 안전하고 신뢰할 수 있는 인증 시스템을 구축할 수 있습니다.

2.1 OAuth2 흐름

OAuth2는 다음과 같은 흐름을 따릅니다:

  1. 사용자가 클라이언트 애플리케이션에서 로그인 요청을 합니다.
  2. 클라이언트 애플리케이션은 인증 서버에 사용자 인증을 요청합니다.
  3. 인증 서버는 사용자 자격 증명을 검증한 후, 클라이언트에 액세스 토큰과 갱신 토큰을 발급합니다.
  4. 클라이언트는 API 요청 시 이 액세스 토큰을 사용하여 보호된 리소스에 접근합니다.

2.2 JWT 구조

JWT는 세 부분으로 구성됩니다:

  • Header: 토큰의 타입과 서명 알고리즘 정보를 포함합니다.
  • Payload: 사용자 정보와 같은 클레임(Claims)를 포함합니다.
  • Signature: Header와 Payload를 인코딩하여 비밀 키로 서명한 값입니다.

3. FastAPI에서 OAuth2와 JWT 구현하기

이제 FastAPI를 사용하여 OAuth2와 JWT를 통한 인증 시스템을 구현해 보겠습니다. 이를 위해 기본적인 FastAPI 애플리케이션을 설정하고, OAuth2와 JWT 로직을 추가하겠습니다.

3.1 FastAPI 애플리케이션 기본 설정


from fastapi import FastAPI

app = FastAPI()

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

위 코드는 FastAPI 애플리케이션의 기본 구조입니다. 이제 이 앱에 OAuth2와 JWT를 구현할 것입니다.

3.2 사용자 모델 및 데이터베이스 설정


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

# 사용자 데이터베이스 시뮬레이션
fake_users_db = {
    "user@example.com": {
        "username": "johndoe",
        "full_name": "John Doe",
        "email": "user@example.com",
        "hashed_password": "$2b$12$KIXyhuOfCJcZawGBY5frXOCeC7g0BU6oq/6kyPzA/9eT4M1Og1Wiy",  # 비밀번호: secret
        "disabled": False,
    }
}

# 유효성 검사 및 해싱 암호화
class User(BaseModel):
    username: str
    full_name: Optional[str] = None
    email: str
    disabled: Optional[bool] = None

class UserInDB(User):
    hashed_password: str

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

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

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

# OAuth2PasswordBearer 설정
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

3.3 사용자 인증


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

# JWT 생성
SECRET_KEY = "your_secret_key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

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

3.4 토큰 경로 추가


@app.post("/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="잘못된 사용자 이름 또는 비밀번호",
            headers={"WWW-Authenticate": "Bearer"},
        )
    access_token_expires = timedelta(minutes=ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": user.email}, expires_delta=access_token_expires
    )
    return {"access_token": access_token, "token_type": "bearer"}

3.5 보호된 경로 추가


@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="유효하지 않은 토큰",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        email: str = payload.get("sub")
        if email is None:
            raise credentials_exception
    except jwt.PyJWTError:
        raise credentials_exception
    user = get_user(fake_users_db, email)
    if user is None:
        raise credentials_exception
    return user

3.6 애플리케이션 실행

모든 설정이 완료되었으면 FastAPI 서버를 실행할 수 있습니다. 아래 명령어를 사용하여 서버를 실행하십시오:

uvicorn main:app --reload

이제 브라우저를 통해 http://127.0.0.1:8000/docs에 접속하여 API 명세를 확인하고, Swagger UI를 통해 API를 테스트할 수 있습니다.

4. 결론

FastAPI와 함께 OAuth2 및 JWT를 사용하여 애플리케이션의 인증 및 권한 부여 시스템을 구현하는 방법을 살펴보았습니다. 이 강좌를 통해 기본적인 사용자 인증 로직을 이해하고 FastAPI에서 어떻게 구현할 수 있는지를 배울 수 있었습니다. 실제 환경에서는 보다 복잡한 요구 사항이 있을 수 있으므로, 추가적인 보안 조치(예: SSL/TLS 암호화, 비밀 키 관리 등)를 고려하는 것이 중요합니다. FastAPI를 사용하여 더 안전하고 강력한 백엔드 애플리케이션을 구축하시길 바랍니다.

FastAPI 서버개발, 보안, FastAPI의 인증 방식

FastAPI는 Python으로 작성된 현대적인 웹 프레임워크로, 뛰어난 성능과 직관적인 문법으로 인기를 끌고 있습니다. 이 글에서는 FastAPI를 사용하여 서버를 개발하는 방법, 보안의 중요성, 그리고 다양한 인증 방법에 대해 자세히 설명하겠습니다.

1. FastAPI 개요

FastAPI는 RESTful API를 빠르게 구축하기 위한 프레임워크입니다. Python의 타입 힌트를 활용하여 코드의 가독성과 유효성을 높이면서, 자동으로 API 문서를 생성하는 기능을 제공합니다. FastAPI는 Starlette와 Pydantic을 기반으로 하여 높은 성능과 데이터 검증 기능을 함께 제공합니다.

2. FastAPI의 설치와 기본 설정

FastAPI와 함께 Uvicorn ASGI 서버를 설치해야 합니다. 다음과 같은 명령어를 사용하여 설치할 수 있습니다:

pip install fastapi uvicorn

2.1 Hello World 예제

FastAPI의 기본적인 구조를 이해하기 위해 간단한 Hello World API를 만들어보겠습니다.


from fastapi import FastAPI

app = FastAPI()

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

위의 코드를 main.py 파일로 저장한 뒤, 다음 명령어로 서버를 실행할 수 있습니다:

uvicorn main:app --reload

이제 브라우저에서 http://127.0.0.1:8000를 열면 “Hello, World” JSON 응답을 확인할 수 있습니다.

3. 서버 보안의 중요성

소프트웨어 개발에서 보안은 매우 중요한 요소입니다. 특히, API를 통해 데이터와 기능에 접근하게 될 경우, 보안이 취약하다면 해킹의 위험성이 높아집니다. FastAPI를 사용할 때는 다음과 같은 보안 요소를 고려해야 합니다:

  • 데이터 암호화
  • 사용자 인증 및 권한 부여
  • 입력 데이터 검증
  • 로그 기록 및 모니터링

4. FastAPI의 인증 방식

FastAPI는 다양한 인증 방식을 지원합니다. 그 중에서 가장 일반적인 방식은 JWT 토큰 인증과 OAuth2입니다. 이번 섹션에서는 JWT 인증 방식을 중심으로 설명하겠습니다.

4.1 JWT( JSON Web Token) 인증

JWT는 두 개의 엔드포인트(로그인과 인증된 사용자 확인)를 통해 사용됩니다. 사용자 정보를 안전하게 저장하고 전달하는 방법 중 하나입니다. JWT 웹 토큰은 주로 사용자 인증 및 정보 교환에 사용되며, 다음과 같은 구조를 가집니다:

  • Header: 토큰의 유형과 서명 알고리즘을 정의합니다.
  • Payload: 사용자 정보나 기타 데이터를 포함합니다.
  • Signature: Header와 Payload를 인코딩하여 비밀 키로 서명한 값입니다.

4.2 FastAPI로 JWT 인증 구현하기

FastAPI에서 JWT 인증을 구현하는 방법은 다음과 같습니다:

4.2.1 필요한 라이브러리 설치

JWT를 사용하기 위해서는 PyJWT와 passlib를 설치해야 합니다. 아래 명령어로 설치할 수 있습니다:

pip install pyjwt passlib[bcrypt]

4.2.2 JWT 유틸리티 함수

토큰 생성 및 검증을 위한 헬퍼 함수를 작성합니다.


import jwt
from datetime import datetime, timedelta
from typing import Dict

SECRET_KEY = "your_secret_key"
ALGORITHM = "HS256"
ACCESS_TOKEN_EXPIRE_MINUTES = 30

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=ACCESS_TOKEN_EXPIRE_MINUTES)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt
    

4.2.3 FastAPI 사용자 모델

사용자 모델을 작성하고, 인증을 위한 엔드포인트를 추가합니다.


from fastapi import FastAPI, Depends, HTTPException
from passlib.context import CryptContext

app = FastAPI()

class User:
    def __init__(self, username: str, password: str):
        self.username = username
        self.password = password

fake_users_db = {
    "johndoe": User(username="johndoe", password="$2b$12$KIXT8j/Nu1H3VzOZL5rO.ulpYb/JgVdY2VZ5ZFkElXju2GZBeY1Fe")
}

pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")

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

def get_user(db, username: str):
    if username in db:
        return db[username]
    return None

@app.post("/token")
async def login(username: str, password: str):
    user = get_user(fake_users_db, username)
    if not user or not verify_password(password, user.password):
        raise HTTPException(
            status_code=401,
            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"}
    

4.2.4 보호된 엔드포인트 생성

인증된 사용자만 접근할 수 있는 보호된 엔드포인트를 추가합니다.


from fastapi import Security
from fastapi.security import OAuth2PasswordBearer

oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")

@app.get("/users/me")
async def read_users_me(token: str = Depends(oauth2_scheme)):
    credentials_exception = HTTPException(
        status_code=401,
        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 jwt.PyJWTError:
        raise credentials_exception
    return {"username": username}
    

5. 결론

FastAPI는 높은 성능과 가독성을 제공하는 훌륭한 웹 프레임워크입니다. 보안은 애플리케이션 개발에 있어 중요한 요소로, JWT 인증은 사용자 인증을 안전하게 수행할 수 있는 방법 중 하나입니다. 이번 글에서 рассмотрены(JWT) 인증 구현 방법을 통해 FastAPI의 발전 가능성과 효율성을 알 수 있는 기회가 되었기를 바랍니다.

FastAPI와 관련하여 더 많은 자료를 참고하시려면 FastAPI 공식 문서를 참조하시기 바랍니다.