fastAPI 를 사용해서 JWT 인증을 구현하고자 합니다.
Windsurf 를 통해서 Claude 3.5 Sonnet 으로 자동생성한 파일을 소개합니다.
구글 로그인을 통해서 JWT 인증을 구현할 때 보안에 취약하지 않도록 해달라고 요청을 했습니다.
일단 ai 는 auth.py 라는 미들웨어 모듈을 생성해주었는데요
이 모듈은 JWT 토큰에 대한 검증을 수행하는 모듈입니다.
"""
JWT(JSON Web Token) 인증을 처리하는 미들웨어 모듈.
이 모듈은 FastAPI 애플리케이션에서 보호된 엔드포인트에 대한 접근을 제어합니다.
"""
from fastapi import Request, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from service.token_service import TokenService
class JWTBearer(HTTPBearer):
"""
JWT 베어러 토큰 인증을 처리하는 커스텀 클래스.
FastAPI의 HTTPBearer를 상속받아 JWT 특화 기능을 추가합니다.
"""
def __init__(self, auto_error: bool = True):
"""
JWTBearer 클래스 초기화
Args:
auto_error (bool): True일 경우 인증 실패 시 자동으로 에러를 발생시킴
"""
super(JWTBearer, self).__init__(auto_error=auto_error)
async def __call__(self, request: Request):
"""
각 요청에 대한 JWT 토큰 검증을 수행하는 메서드
Args:
request (Request): FastAPI의 요청 객체
Returns:
str: 유효한 JWT 토큰 문자열
Raises:
HTTPException: 인증 실패 시 403 Forbidden 에러 발생
"""
# 상위 클래스의 __call__ 메서드를 호출하여 인증 정보 추출
credentials: HTTPAuthorizationCredentials = await super(JWTBearer, self).__call__(request)
# 인증 정보가 없는 경우 에러 발생
if not credentials:
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Invalid authorization code"
)
# Bearer 토큰 방식이 아닌 경우 에러 발생
if credentials.scheme != "Bearer":
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail="Invalid authentication scheme"
)
try:
# JWT 토큰 검증 및 페이로드 추출
payload = TokenService.verify_token(credentials.credentials)
# 요청 상태에 사용자 ID 저장 (후속 처리에서 사용 가능)
request.state.user_id = int(payload.get("sub"))
except Exception as e:
# 토큰 검증 실패 시 에러 발생
raise HTTPException(
status_code=status.HTTP_403_FORBIDDEN,
detail=str(e)
)
return credentials.credentials
# 전역 JWT 베어러 인스턴스 생성
jwt_bearer = JWTBearer()
아래는 ai 를 통해 요청한 설명의 내용입니다.
auth.py 파일의 전체적인 구조와 동작을 설명하겠습니다:
1. 파일의 목적:
- JWT(JSON Web Token) 기반의 인증을 처리하는 미들웨어를 구현합니다.
- FastAPI 애플리케이션에서 보호된 엔드포인트에 대한 접근 제어를 담당합니다.
2. 주요 컴포넌트:JWTBearer 클래스:
- FastAPI의 HTTPBearer를 상속받아 JWT 인증을 처리하는 커스텀 클래스
- jwt_bearer 인스턴스: 애플리케이션 전역에서 사용할 수 있는 인증 핸들러 인스턴스
3. 인증 프로세스:
- 클라이언트가 보호된 엔드포인트에 요청을 보낼 때 Authorization 헤더에 JWT 토큰을 포함시켜야 합니다.
- call 메서드가 요청을 가로채서:
* 인증 정보의 존재 여부 확인
* Bearer 토큰 방식인지 확인
* JWT 토큰의 유효성 검증
* 토큰에서 사용자 ID 추출 및 요청 상태에 저장
4. 에러 처리:
- 인증 정보 누락
- 잘못된 인증 방식
- 유효하지 않은 JWT 토큰 위의 경우들에 대해 403 Forbidden 응답을 반환합니다.
이 미들웨어는 보안이 필요한 엔드포인트에 쉽게 적용할 수 있으며, JWT 토큰 기반의 견고한 인증 시스템을 제공합니다.
이 방식에 따라 보호가 필요한 엔드포인트와 라우터마다 jwt_bearer 의존성을 추가하도록 합니다.
아래는 엔드포인트에 적용한 내용입니다.
@router.get("/", response_model=List[User], dependencies=[Depends(jwt_bearer)])
def read_users(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)):
return UserService.get_users(db=db, skip=skip, limit=limit)
@router.put("/{user_id}", response_model=User, dependencies=[Depends(jwt_bearer)])
def update_user(user_id: int, user: UserUpdate, db: Session = Depends(get_db)):
return UserService.update_user(db=db, user_id=user_id, user=user)
아래는 라우터에 적용한 것입니다.
router = APIRouter(
prefix="/api/categories",
tags=["categories"],
responses={404: {"description": "Not found"}},
dependencies=[Depends(jwt_bearer)] # 모든 카테고리 엔드포인트에 JWT 인증 적용
)
이렇게 적용함으로 보호된 엔드포인트에 접근하려면 반드시 유효한 JWT 토큰이 필요하며, 토큰이 없거나 유효하지 않은 경우 403 Forbidden 에러가 발생합니다.
클라이언트는 Authorization 헤더에 Bearer <token> 형식으로 토큰을 포함시켜야 합니다.
로그인 후 개발자도구를 통해서 로컬저장소를 확인하면 토큰이 들어가 있는 것을 확인할 수 있습니다.
'Python' 카테고리의 다른 글
python 에서 화면 생성을 위해 사용중인 Jinja2Templates (0) | 2025.04.05 |
---|---|
fastAPI + JWT 인증 2 - 토큰 생성 및 검증, 관리 (0) | 2025.04.05 |
KOSIS 통계정보를 이용한 데이터 조회 방법 (0) | 2025.03.29 |
python+fastAPI+postgresql 로 구성된 환경에서 간단한 CRUD 구현2 (0) | 2025.03.28 |
python+fastAPI+postgresql 로 구성된 환경에서 간단한 CRUD 구현1 (0) | 2025.03.28 |