-
TIL.78 JWT Token 유효시간 설정TIL 2020. 12. 26. 21:07728x90
이전까지는 로그인시 jwt를 포함한 응답을 함께 전송하였으며
우리 서비스를 사용하는 사용자가 맞는지, 유로서비스를 이용 중인 사용자는 맞는지 등
인가를 이용해 토큰이 우리 서비스에서 발행된 토큰이 맞는지에 따라 접근권한을 부여하였다.
토큰은 만료시간을 설정해줄 수 있다.
보통 로그인후, 토큰을 생성하여 응답으로 전달해준다.
사용자의 토큰 정보는 브라우저 스토리지에 저장해놓은 상태로 로그인한 사용자가 어떠한 기능/페이지에 접근하기 위해 전체 요청이 아닌 세션ID/토큰만으로 요청을 보내 사용된다.
이때 만료시간을 설정하지 않으면 토큰이 계속 만료되어 게시물을 하나 등록하고 또 다른 게시물을 등록하고 싶을때 다시 로그인해야하는 번거로움이 발생한다.
실제로는 이전처럼 만료시간을 설정하지 않는 토큰은 사용되지 않는다.
대부분 로그인한 후 만료시간을 설정하여 몇분, 몇시간 후 다시 로그인을 하여 토큰을 갱신해주는 방식으로 사용한다.
쇼핑몰에서 장바구니를 담고 찜하고 구매하고 모든 과정을 할때마다 일일이 로그인을 해야한다면??? 굉장히 불편할 것이다.
이제 토큰에 만료시간을 부여하기 위해
현재로부터 일정 시간이 지난 시점까지 토큰의 만료시간을 설정하는 법을 알아보자
토큰은 기본적으로 Header(헤더)와 Payload(페이로드), Signature(시그니쳐)로 나뉘는데,
만료시간(유효시간)은 claim set이라고도 불리는 페이로드에 저장할 수 있다.
payload 에는 토큰 만료시간이나 발급자, 제목과 같은 등록된 클레임이나 우리가 담고 싶은 내용을 담을 수 있는 공개/비공개 클레임을 담을 수 있다.
비공개 클레임은 클라이언트/서버 간에 서로 약속한 내용, 예를 들면 로그인 아이디 등 DB에서 저장되어 있는 정보를 을 담는 역할을 한다다.
아래 코드처럼 exp 부분에 만료시간을 설정하였다.
exp로 만료시간을 설정하는게 컨벤션으로 보인다.
1. datetime.now() 토큰이 발행되는 현재 시간을 불러오는 메서드
2. timedelta() 특정시간을 더하고 뺄때 사용하는 메서드
from datetime import datetime, timedelta payload = {'username': user.id, 'exp': datetime.now() +timedelta(hours=2)} access_token = jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM) return JsonResponse({'message': 'SUCCESS', 'access_token': access_token.decode('utf-8')}, status=200)
timedelta는 인자로 seconds, hours, days, weeks 를 받고, '='를 넣어서 시간을 표현한다.
현재시간 기준 3일 후를 유효기간으로 사용하고 싶다면 위의 예시처럼 timedelta(days=3)을 더해주면 되고, 3주면 timedelta(weeks=3)을 넣어주면 된다.
months나 years는 좀 다르게 아래처럼 사용한다고 한다.
from dateutil.relativedelta import relativedelta exp = datetime.utcnow() - relativedelta(months=3)
토큰 인가
이제 유효기간을 설정했으니, 사용자의 토큰을 확인할 때 이 유효기간을 통해 토큰이 유효한지 확인해야합니다. 일단 토큰이 유효한지 자체는 토큰을 decode 하는 과정에서 자동으로 진행해주기 때문에 따로 설정을 할 필요는 없습니다.
만료된 토큰을 넣어서 디코드를 진행하면 아래와 같은 에러가 나타난다.
jwt.exceptions.ExpiredSignatureError: Signature has expired
말 그대로 토큰의 시그니쳐가 만료됐다는 얘긴데
이 에러를 Exception 로직에 넣어 처리해줘야한다.
except jwt.ExpiredSignatureError: return JsonResponse({"message": "EXPIRED_TOKEN"}, status = 400)
from datetime import datetime, timedelta class SignInView(View): def post(self, request): data = json.loads(request.body) user = User.objects.get(username=data['username']) if not bcrypt.checkpw(data['password'].encode('utf-8'), user.password.encode('utf-8')): return JsonResponse({'message': 'INVALID_PASSWORD'}, status=401) payload = {'username': user.id, 'exp': datetime.now() +timedelta(hours=2)} access_token = jwt.encode(payload, SECRET_KEY, algorithm=ALGORITHM) return JsonResponse({'message': 'SUCCESS', 'access_token': access_token.decode('utf-8')}, status=200)
여기서 Acccess_token에 대해 간단히 정리해보자
사용자가 로그인을 할 때 클라이언트에게 AccessToken을 발급한다.
서버는 AccessToken을 데이터베이스나 파일등에 저장 할 필요 없이 메모리상에서 미리 정의 된 비밀키를 이용해 비교하는 것 만으로 인증을 처리하기 때문에 추가적인 I/O 작업이 필요가 없다.
하지만 몇가지 단점이 있다.
- 토큰 만료 기간이 짧아, 자주 로그인을 다시 해야한다.
- 한번 생성된 토큰은 제거되지 않는다.
사실 이전까지 사용하였던 Access_token은 여러가지의 단점이 있어 단독으로 쓰이는 경우는 없다고 한다.
추후 Access_token 의 단점을 보완하기 위해 사용되고 있는 Sliding Sessions // Refresh Token에 대해서도 알아보자!!
출처 및 참고:
JWT 토큰 유효시간 설정(feat. timedelta) (velog.io)
TIL.64 (Token)_Authentication :: muntari Log (tistory.com)
TIL.61 Bcrypt, Pyjwt (암호화) :: muntari Log (tistory.com)
728x90'TIL' 카테고리의 다른 글
TIL.80 AWS_실습2_EC2 & RDS 연동 및 배포 (0) 2020.12.28 TIL.79 AWS_EC2_실습 (0) 2020.12.27 TIL.77 List Comprehension의 속도가 빠른이유 (0) 2020.12.24 TIL.76 AWS (0) 2020.12.23 TIL.75 RSETfulAPI (0) 2020.12.22