ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • FastAPI 시리즈 12화 - JWT 기반 인증 시스템 완성: 토큰 구조와 보안 처리 심화
    기술과 산업/언어 및 프레임워크 2025. 5. 30. 01:20
    728x90

    FastAPI에서 JWT(Json Web Token)의 구조, 만료 처리, 리프레시 토큰 전략, 서명 보안 방식 등을 실전 중심으로 다룹니다. 인증 시스템을 안전하게 완성하는 방법을 소개합니다.

     

    왜 JWT 구조를 이해해야 하는가?

     

    JWT(Json Web Token)는 다음과 같은 구조로 구성됩니다:

    HEADER.PAYLOAD.SIGNATURE

    파트설명

    Header 알고리즘 및 타입 (alg, typ)
    Payload 사용자 데이터 (sub, exp, role 등)
    Signature 서버 비밀키로 서명된 무결성 보장 부분

    JWT는 읽을 수 있지만 조작할 수 없어야 합니다.

    따라서 서명(Signature)을 검증하지 않으면, 누구나 위조된 토큰을 만들 수 있게 됩니다.

     


     

    1. JWT 유효성 검증 강화

    from jose import jwt, JWTError
    from fastapi import HTTPException
    
    def verify_token(token: str):
        try:
            payload = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
            return payload
        except JWTError:
            raise HTTPException(status_code=401, detail="Invalid token")

     

    • jwt.decode()는 signature 검증 + 만료 확인까지 자동 수행
    • JWTError로 모든 오류 포착 가능
    • signature가 일치하지 않으면 인증 실패

     


     

    2. 토큰 만료 시간 처리 (exp)

    from datetime import datetime, timedelta
    
    def create_access_token(data: dict, expires_delta: 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)

     

    • exp 필드는 ISO UTC 기준으로 입력
    • Swagger에서 만료된 토큰은 즉시 401 반환됨

     


     

    3. 리프레시 토큰 전략 설계

     

     

    📌 왜 필요한가?

     

    • 액세스 토큰은 수명이 짧아야 보안에 유리 (15~30분)
    • 매번 로그인할 수 없기 때문에 장기 보관용 리프레시 토큰이 필요

     

     

    📌 리프레시 토큰 흐름

    1. 로그인 성공 → access_token + refresh_token 발급
    2. access_token 만료 시 → refresh_token으로 재발급 요청
    3. refresh_token은 DB나 Redis에서 상태 관리

     


     

    4. 리프레시 토큰 발급 예제

    def create_refresh_token(data: dict):
        expire = datetime.utcnow() + timedelta(days=7)
        data.update({"exp": expire})
        return jwt.encode(data, SECRET_KEY, algorithm=ALGORITHM)
    @app.post("/token/refresh")
    def refresh_token(refresh_token: str):
        try:
            payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=[ALGORITHM])
            username = payload.get("sub")
            # 추가 검증: DB에서 refresh_token 유효성 확인 필요
            new_access = create_access_token({"sub": username})
            return {"access_token": new_access}
        except JWTError:
            raise HTTPException(status_code=401, detail="Invalid refresh token")

     


     

    5. 실무 보안 강화 포인트

    항목설명

    비밀번호 해싱 bcrypt 활용 (pip install passlib[bcrypt])
    토큰 블랙리스트 로그아웃 시 refresh_token 무효화 (DB나 Redis 활용)
    HTTPS 적용 토큰 유출 방지를 위해 항상 TLS 사용
    secure, httponly 쿠키 토큰을 쿠키에 저장 시 필수 설정
    사용자 역할(Role) 기반 제어 JWT Payload에 role 포함 후 접근 제어 적용

     


     

    6. 사용자 권한(Role) 기반 API 접근 제어

    def get_admin_user(token: str = Depends(oauth2_scheme)):
        payload = verify_token(token)
        if payload.get("role") != "admin":
            raise HTTPException(status_code=403, detail="Admins only")
        return payload
    
    @app.get("/admin/dashboard")
    def read_admin_dashboard(user=Depends(get_admin_user)):
        return {"message": f"Welcome {user['sub']}, to the admin dashboard"}

     

    • JWT에 사용자 role 정보를 포함시키고
    • 인증 함수에서 권한 확인 로직을 분리

     


     

    FastAPI 인증 시스템을 진짜 서비스 수준으로 완성하려면

    항목적용 방법

    JWT 발급 sub, exp 포함 후 서명
    토큰 만료 timedelta 기반 설정
    리프레시 토큰 별도 토큰 발급 + 상태 관리
    사용자 권한 제어 JWT에 role 필드 포함
    보안 강화 HTTPS, bcrypt, 토큰 저장소, 쿠키 옵션 등 적용 필요

    FastAPI는 인증을 “쉽게 시작할 수 있으면서도, 깊이 있게 확장 가능한 구조”로 설계되어 있습니다.

    이제 로그인 기능을 넘어서 서비스 전반의 인증/보안 흐름을 스스로 구성할 수 있는 수준까지 도달한 것입니다.

     


     

    다음 글 예고

     

    FastAPI 시리즈 13화 - 사용자 권한(Role) 관리와 종속성 적용 방법

    에서는 사용자 계층별 접근 제어를 어떻게 분리하고, Depends를 활용해 권한 시스템을 구현하는지를 설명합니다.

    728x90
Designed by Tistory.