본문 바로가기
Coding/Python

Django Restframework JWT 토큰 인증 커스터마이징

by Hide­ 2018. 6. 28.
반응형


Django의 DRF에서는 djangorestframework-jwt라는 라이브러리를 사용하면 쉽게 토큰을 사용할 수 있다.

기존에는 그냥 import jwt를 통하여 작업을 했었는데 이렇게 라이브러리를 올려놓고 사용하다 보니 뭔가 헷갈렸다.

편하게 사용하자고 설치한 라이브러리인데 오히려 더 불편한 느낌이랄까.

내가 이해를 제대로 못하는건지 모르겠지만 개인적으로 장고 관련 자료들은 Document들이 전부다 부실한 느낌이다.

오늘은 내가 겪었던 불편사항들과 그 해결 방법에 대해 적어본다.

먼저 위 라이브러리를 사용하면 쉽게 토큰 발급, 토큰 재발행 등의 작업을 할 수 있다.

하지만 문제점은 실제 view에서 작업할 때 해당 라이브러리들을 어떻게 엮어줘야할까 였다.

라이브러리를 까보고 싶지 않았지만 어쩔수 없이 직접 소스를 분석해가며 문제를 해결했다.

의식의 흐름기법으로 작성하다보니 무슨말을 하려는지 명확하게 안써놓은 것 같은데,

한마디로, 페이로드에 내가 원하는 값을 담는 방법과 views에서 페이로드 디코드 함수를 사용하는 방법에 대해서 설명한다.

먼저 공식 문서(https://getblimp.github.io/django-rest-framework-jwt/)를 한번 살펴본다.

아래로 조금 내리다 보면 JWT_AUTH 쪽에


'JWT_PAYLOAD_HANDLER': 'rest_framework_jwt.utils.jwt_payload_handler', 'JWT_PAYLOAD_GET_USER_ID_HANDLER': 'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',


와 같은 내용이 나온다. 아마 페이로드 관련해서 jwt_payload_handler함수를 건드려야할 것 같다.

그래서 깃헙으로 들어가서 소스를 확인해보니 다음과 같았다.


def jwt_payload_handler(user):
username_field = get_username_field()
username = get_username(user)

warnings.warn(
'The following fields will be removed in the future: '
'`email` and `user_id`. ',
DeprecationWarning
)

payload = {
'user_id': user.pk,
'username': username,
'exp': datetime.utcnow() + api_settings.JWT_EXPIRATION_DELTA
}
if hasattr(user, 'email'):
payload['email'] = user.email
if isinstance(user.pk, uuid.UUID):
payload['user_id'] = str(user.pk)

payload[username_field] = username

# Include original issued at time for a brand new token,
# to allow token refresh
if api_settings.JWT_ALLOW_REFRESH:
payload['orig_iat'] = timegm(
datetime.utcnow().utctimetuple()
)

if api_settings.JWT_AUDIENCE is not None:
payload['aud'] = api_settings.JWT_AUDIENCE

if api_settings.JWT_ISSUER is not None:
payload['iss'] = api_settings.JWT_ISSUER

return payload


대충 보면 알겠지만 중간쯤 payload = {} 부분에 원하는 값을 포함시킬 수 있다.

이렇게 수정한 내용을 반영해주려면 settings.py를 바꿔줘야 한다.


JWT_AUTH = {
'JWT_PAYLOAD_HANDLER': 'article.utils.jwt_payload_handler',

}

예를 들어 위와 같이 적는다면 JWT_PAYLOAD_HANDLER는 article의 utils.py파일에 있는 jwt_payload_handler 함수를 사용하겠다는 말이다.

또한 views에서 토큰을 가져와서 디코드하는 방법은 아래와 같다.


from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework_jwt.utils import jwt_decode_handler

def token_decode(request):
auth = JSONWebTokenAuthentication()
jwt_value = auth.get_jwt_value(request)
payload = jwt_decode_handler(jwt_value)
return payload


많은 클래스에서 불러와 사용해야하기 때문에 views.py의 상단 부분에 해당 함수를 선언해주고,

각 클래스에서 사용할 때마다 request를 인자로 주어 사용하면 된다.

위처럼 하면 payload['username']등의 형태로 값에 접근할 수 있다.