JWT 토큰 만들기

JWT 토큰 만들고 검증하기

만들고자 하는 것

인증 정보를 JWT 로 만들어 사용하도록 하고 싶다.

만들기

FastAPI 의 공식 문서 중 oAuth2 with Password (and hashing), Bearer with JWT tokens 를 참고하여 만들었다.

패키지 설치

아래 pip 구문대로 설치를 진행하면 2가지가 설치가 된다.

  • cryptography
  • python-jose
pip install "python-jose[cryptography]"  

JWT 토큰 만들기

util/security.py 에 추가한다.

기본 정보 setup

  • secret_key : 암호화 키
  • algorithm : 암호화 알고리즘
  • access_token_expire_minutes : 토큰 만료 시간

secret_key 의 경우 임의로 생성해서 사용해도 된다. 필자는 openssl 명령어를 사용하여 랜덤한 값을 사용했다.

openssl rand -hex 32
SECRET_KEY = "1fe606aaf688d41ba969e0cab278698dfff6db46465542f703dd183035dfdc5d"
ALGORITHM = "HS512"
ACCESS_TOKEN_EXPIRE_MINUTES = 60 * 24

Handle JWT tokens

토큰 생성 함수

from datetime import timedelta, datetime
from passlib.context import CryptContext
from jose import JWTError, jwt
from model.jwt import TokenData

만료 시간을 따로 주지 않으면 기본 값으로 1시간을 부여하였다.

def create_access_token(data: dict, expires_delta: timedelta | None = None):
    to_encode = data.copy()
    if expires_delta:
        expire = datetime.utcnow() + expires_delta
    else:
        expire = datetime.utcnow() + timedelta(minutes=60)
    to_encode.update({"exp": expire})
    encoded_jwt = jwt.encode(to_encode, SECRET_KEY, algorithm=ALGORITHM)
    return encoded_jwt

create_access_token 을 사용해서 출력해보면 아래와 같이 . 이 2개로 3영역이 나누어진 문자열이 출력이 된다.

eyJhbGciOiJIUzUxMiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJ0ZXN0IiwibmFtZSI6ImFwZWx0b3AiLCJleHAiOjE2ODY2Mzk3NjR9.aQAbnwZw_btAV_oUB8a7A7ttW7AhmvWwm1SN1gMW0Y8m8hz8Blil4aMnr-hWjf1v5yp9jZeWOX2cojdPZlXl5w 

이 값을 가지고 jwt.io 에 접속하여 디코딩을 해보면 아래와 같이 header 와 payload 부분을 볼 수 있다. SECRET_KEY 가 있어야만 실제로 유효한지 확인할 수 있다.

31-1.png

토큰 검증 함수

토큰 검증은 secret_key 를 가지고 검증을 하게 된다. 또한 유효하다면 payload 의 값을 반환하도록 한다.

def decode_access_token(token: str, secret_key: str = SECRET_KEY, algorithm: str = ALGORITHM):
    try:
        return jwt.decode(token, secret_key, algorithms=[algorithm])
    except JWTError:
        raise JWTError

테스트 케이스 작성

테스트 케이스는 간단하게 3개 작성하였다.

  • 토큰 생성
  • 토큰 검증 성공
  • 토큰 검증 실패
    def test_access_token(self):
        token = create_access_token({'sub': 'test', 'name': 'apeltop'})
        header = jwt.get_unverified_header(token)

        self.assertEqual(header, {
            'alg': 'HS512',
            'typ': 'JWT'
        })

    def test_decode_token_success(self):
        data = {'sub': 'test', 'name': 'apeltop'}
        token = create_access_token(data)
        payload = decode_access_token(token)

        self.assertEqual(payload['sub'], data['sub'])
        self.assertEqual(payload['name'], data['name'])

    def test_decode_token_fail(self):
        data = {'sub': 'test', 'name': 'apeltop'}
        token = create_access_token(data)

        with self.assertRaises(JWTError) as e:
            decode_access_token(token, secret_key='WRONG_TOKEN')

이제 실제 로그인 성공했을 때 토큰을 부여하기 위한 작업 밑바탕은 된 것이다.


리팩터링 - router 분리하기
NCloud LB & SourcePipeline 구축하기
tech collection 서비스 성능 개선하기
Selenium 복권 구매 자동화 만들어보기
디자인 패턴
책 리뷰
블로그 챌린지