djangorestframework-jwtを使わない理由
理由としては大きく2つがありました。
- 理由1:もうサポートしてない。(2017年が最後のrelease.)
- securityに問題が発生する。(CVE-2018-0114など。)
- 理由2:refresh_tokenとaccess_tokenを同時に得られない。
- これがきっかけ
Django-simplejwt
は access_tokenとrefresh_tokenを同時得られる。
djangorestframework-jwt → djangorestframework-simplejwt
まず、djangorestframework-simplejwtからinstallする。
pip install djangorestframework-simplejwt
django-rest-authのdirectory構造。このファイルのうち直すファイルはutils.py
。
├── __init__.py
├── __init__.pyc
├── __pycache__
│ ├── __init__.cpython-38.pyc
│ ├── admin.cpython-38.pyc
│ ├── app_settings.cpython-38.pyc
│ ├── models.cpython-38.pyc
│ ├── serializers.cpython-38.pyc
│ ├── social_serializers.cpython-38.pyc
│ ├── urls.cpython-38.pyc
│ ├── utils.cpython-38.pyc
│ └── views.cpython-38.pyc
├── admin.py
├── admin.pyc
├── app_settings.py
├── app_settings.pyc
├── locale
│ ├── cs
│ │ └── LC_MESSAGES
│ │ ├── django.mo
│ │ └── django.po
│ ├── de
│ │ └── LC_MESSAGES
│ │ ├── django.mo
│ │ └── django.po
│ ├── es
│ │ └── LC_MESSAGES
│ │ ├── django.mo
│ │ └── django.po
│ ├── ko
│ │ └── LC_MESSAGES
│ │ ├── django.mo
│ │ └── django.po
│ ├── pl
│ │ └── LC_MESSAGES
│ │ ├── django.mo
│ │ └── django.po
│ ├── ru
│ │ └── LC_MESSAGES
│ │ ├── django.mo
│ │ └── django.po
│ ├── tr
│ │ └── LC_MESSAGES
│ │ └── django.po
│ ├── zh_Hans
│ │ └── LC_MESSAGES
│ │ ├── django.mo
│ │ └── django.po
│ └── zh_Hant
│ └── LC_MESSAGES
│ ├── django.mo
│ └── django.po
├── models.py
├── models.pyc
├── registration
│ ├── __init__.py
│ ├── __init__.pyc
│ ├── __pycache__
│ │ ├── __init__.cpython-38.pyc
│ │ ├── app_settings.cpython-38.pyc
│ │ ├── serializers.cpython-38.pyc
│ │ ├── urls.cpython-38.pyc
│ │ └── views.cpython-38.pyc
│ ├── app_settings.py
│ ├── app_settings.pyc
│ ├── serializers.py
│ ├── serializers.pyc
│ ├── urls.py
│ ├── urls.pyc
│ ├── views.py
│ └── views.pyc
├── serializers.py
├── serializers.pyc
├── social_serializers.py
├── social_serializers.pyc
├── tests
│ ├── __init__.py
│ ├── __init__.pyc
│ ├── __pycache__
│ │ ├── __init__.cpython-38.pyc
│ │ ├── django_urls.cpython-38.pyc
│ │ ├── mixins.cpython-38.pyc
│ │ ├── settings.cpython-38.pyc
│ │ ├── test_api.cpython-38.pyc
│ │ ├── test_social.cpython-38.pyc
│ │ └── urls.cpython-38.pyc
│ ├── django_urls.py
│ ├── django_urls.pyc
│ ├── mixins.py
│ ├── mixins.pyc
│ ├── requirements.pip
│ ├── settings.py
│ ├── settings.pyc
│ ├── test_api.py
│ ├── test_api.pyc
│ ├── test_base.pyc
│ ├── test_social.py
│ ├── test_social.pyc
│ ├── urls.py
│ └── urls.pyc
├── urls.py
├── urls.pyc
├── utils.py #<ーーこれ
├── utils.pyc
├── views.py
└── views.pyc
utils.py
の中を見ると、jwt_encode
って書いてある関数があってその中は次のようになっていてこのコードを下のコードに変える。
(https://django-rest-framework-simplejwt.readthedocs.io/en/latest/creating_tokens_manually.html)
def jwt_encode(user):
try:
from rest_framework_jwt.settings import api_settings
except ImportError:
raise ImportError("rest_framework_simplejwt needs to be installed")
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
payload = jwt_payload_handler(user)
return jwt_encode_handler(payload)
↓
def jwt_encode(user):
try:
# from rest_framework_jwt.settings import api_settings <-- old version.
from rest_framework_simplejwt.tokens import RefreshToken
except ImportError:
raise ImportError("rest_framework_simplejwt needs to be installed")
# jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
# jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
# payload = jwt_payload_handler(user)
refresh = RefreshToken.for_user(user)
payload = {'refresh' : str(refresh), 'access': str(refresh.access_token)}
return payload
その後、serializers.py
のコードも下のように直す。
class JWTSerializer(serializers.Serializer):
"""
Serializer for JWT authentication.
"""
token = serializers.CharField()
user = serializers.SerializerMethodField()
def get_user(self, obj):
"""
Required to allow using custom USER_DETAILS_SERIALIZER in
JWTSerializer. Defining it here to avoid circular imports
"""
rest_auth_serializers = getattr(settings, 'REST_AUTH_SERIALIZERS', {})
JWTUserDetailsSerializer = import_callable(
rest_auth_serializers.get('USER_DETAILS_SERIALIZER', UserDetailsSerializer)
)
user_data = JWTUserDetailsSerializer(obj['user'], context=self.context).data
return user_data
↓
class JWTSerializer(serializers.Serializer):
"""
Serializer for JWT authentication.
"""
token = serializers.JSONField()
user = serializers.SerializerMethodField()
def get_user(self, obj):
"""
Required to allow using custom USER_DETAILS_SERIALIZER in
JWTSerializer. Defining it here to avoid circular imports
"""
rest_auth_serializers = getattr(settings, 'REST_AUTH_SERIALIZERS', {})
JWTUserDetailsSerializer = import_callable(
rest_auth_serializers.get('USER_DETAILS_SERIALIZER', UserDetailsSerializer)
)
user_data = JWTUserDetailsSerializer(obj['user'], context=self.context).data
return user_data
Before & After
Before
{
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyLCJ1c2VybmFtZSI6InVzZXIiLCJleHAiOjE1OTk5MzQ0NDYsImVtYWlsIjoiIn0.ddZRKpU76x66dkJVh0SEP3FZL1HHLv8XJqvaf8OEd5o",
"user": {
"pk": 2,
"username": "user",
"email": "",
"first_name": "",
"last_name": ""
}
}
After
{
"token": {
"refresh": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoicmVmcmVzaCIsImV4cCI6MTYwMDAyMDYzMSwianRpIjoiNTEwNzhlZmU4MGY2NDNiYjkyYmUyMTlkMDc5OWM1ZTIiLCJ1c2VyX2lkIjoyfQ.eGzYcmAD5e7Oi_DnN9N0j0iMswiCnBc8Qwoeltnlhos",
"access": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ0b2tlbl90eXBlIjoiYWNjZXNzIiwiZXhwIjoxNTk5OTM0NTMxLCJqdGkiOiI1ZTA1N2U5NThlM2I0NDgzODA4ZDkyNWFlODljMTMzYyIsInVzZXJfaWQiOjJ9.OFX7jYeco6uNK_WenOdO5jKJkN-RwMiwFZa1zhusoUA"
},
"user": {
"pk": 2,
"username": "user",
"email": "",
"first_name": "",
"last_name": ""
}
}
確認した結果、dj-rest-authって言う新しいpackageがあるらしいのでdj-rest-authを使ってください。
こちらは、simple-jwtを使ってます。