JWT 토큰 유효시간 설정(feat. timedelta)

jomminii_before·2020년 4월 5일
13

이전 글( Django - 회원가입/로그인 앱생성 개선(ver 1.2)암호화 및 토큰 발행)에서 JWT 토큰을 발행하는 사례를 소개한 적이 있었는데요, 이때는 토큰의 유효기간(만료기간)을 따로 설정하지 않았습니다. 테스트 환경이라 토큰이 계속 만료되면 번거롭기도 해서 뭐 이런저런 이유가 있었습니다.

그래서 이번에는 timedelta를 이용해 현재로부터 일정 기간이 지난 시점까지 토큰의 유효기간을 설정하는 법을 알아보겠습니다.

일단 기본적인 JWT 토큰을 발행할 수 있다는 가정하에 아래와 같이 토큰 발행을 진행합니다.
토큰은 기본적으로 Header(헤더)Payload(페이로드), Signature(시그니쳐)로 나뉘는데, 유효기간은 claim set이라고도 불리는 페이로드에 저장할 수 있습니다.

페이로드에는 토큰 만료시간이나 발급자, 제목과 같은 등록된 클레임이나 우리가 담고 싶은 내용을 담을 수 있는 공개/비공개 클레임을 담을 수 있습니다. 비공개 클레임은 클라이언트/서버 간에 서로 약속한 내용, 예를 들면 로그인 아이디 등을 담는 역할을 합니다.

등록된 클레임은 벨로퍼트님이 쓰신걸로 갈음하겠습니다.

iss: 토큰 발급자 (issuer)
sub: 토큰 제목 (subject)
aud: 토큰 대상자 (audience)
exp: 토큰의 만료시간 (expiraton), 시간은 NumericDate 형식으로 되어있어야 하며 (예: 1480849147370) 언제나 현재 시간보다 이후로 설정되어있어야합니다.
nbf: Not Before 를 의미하며, 토큰의 활성 날짜와 비슷한 개념입니다. 여기에도 NumericDate 형식으로 날짜를 지정하며, 이 날짜가 지나기 전까지는 토큰이 처리되지 않습니다.
iat: 토큰이 발급된 시간 (issued at), 이 값을 사용하여 토큰의 age 가 얼마나 되었는지 판단 할 수 있습니다.
jti: JWT의 고유 식별자로서, 주로 중복적인 처리를 방지하기 위하여 사용됩니다. 일회용 토큰에 사용하면 유용합니다.

아래의 코드를 보면, exp 에 만료기간을 설정하였습니다.

from datetime import datetime, timedelta

token = jwt.encode(
	{'login_id':data['login_id'], 'exp':datetime.utcnow() + timedelta(days=3)},
    SECRET_KEY, algorithm = 'HS256')

exp 부분을 보면 datetime.utcnow()라는 현재 시간을 불러오는 메서드와 timedelta라는 특정 시간을 더하고 뺄때 사용하는 메서드가 들어있습니다. 둘 다 datetime에서 불러온 모듈을 사용합니다.

참고로 datetime.utcnow()는 UTC 기준으로 시간을 불러오기 때문에, 실제 사용하는 시간대에 맞춰서 변경해 사용하셔야 합니다.

timedelta는 인자로 seconds, hours, days, weeks 를 받고, '='를 넣어서 시간을 표현합니다. 현재시간 기준 3일 후를 유효기간으로 사용하고 싶다면 위의 예시처럼 timedelta(days=3)을 더해주면 되고, 3주면 timedelta(weeks=3)을 넣어주면 됩니다.

monthsyears는 좀 다르게 아래처럼 사용한다고 하네요.

from dateutil.relativedelta import relativedelta
exp =  datetime.utcnow() - relativedelta(months=3)

이제 유효기간을 설정했으니, 사용자의 토큰을 확인할 때 이 유효기간을 통해 토큰이 유효한지 확인해야합니다. 일단 토큰이 유효한지 자체는 토큰을 decode 하는 과정에서 자동으로 진행해주기 때문에 따로 설정을 할 필요는 없습니다.

만료된 토큰을 넣어서 디코드를 진행하면 아래와 같은 에러가 나타납니다.

jwt.exceptions.ExpiredSignatureError: Signature has expired

말 그대로 토큰의 시그니쳐가 만료됐다는 얘긴데요, 이 에러를 Exception 로직에 넣어 처리해줘야합니다. 다행히 JWT 내에 에러를 잡아주는 녀석이 있어서 아래와 같이 에러를 캐치해 리턴을 넣어주면 됩니다.

except jwt.ExpiredSignatureError:
    return JsonResponse({"message": "EXPIRED_TOKEN"}, status = 400)

이제 어느정도 이해가 가시는지 모르겠네요. 다음엔 리프레스 토큰에 대해서 알아봐야겠습니다.

참고자료

profile
https://velog.io/@jomminii 로 이동했습니다.

2개의 댓글

comment-user-thumbnail
2020년 8월 11일

장고는 가볍게 알아도, jwt에 대해선 많이 몰랐었는데, 덕분에 어떻게 장고에서 jwt으로 인증을 처리할 지 배웠습니다. 많이 배우고 갑니다 감사합니다 :-)

답글 달기
comment-user-thumbnail
2020년 12월 27일

감사합닏다 많은 도움이되었습니다!!

답글 달기