[PYTHON] I changed the jwt token generator to simplejwt with Django Rest Auth.

Why not use djangorestframework-jwt

There were two main reasons.

--Reason 1: No longer supported. (2017 is the last release.) --There is a security problem. (CVE-2018-0114 etc.) --Reason 2: You cannot get refresh_token and access_token at the same time. ――This was the trigger

Django-simplejwt gets access_token and refresh_token at the same time.

djangorestframework-jwt → djangorestframework-simplejwt

First, install from djangorestframework-simplejwt.

pip install djangorestframework-simplejwt

The directory structure of django-rest-auth. The file to be fixed in this file is ʻ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 # <-this
├── utils.pyc
├── views.py
└── views.pyc

If you look inside ʻutils.py, there is a function that says jwt_encode`, and it looks like this, and change this code to the code below.

(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

After that, fix the code of serializers.py as below.

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": ""
  }
}

As a result of checking, it seems that there is a new package called dj-rest-auth, so use dj-rest-auth please. This uses simple-jwt.

Recommended Posts

I changed the jwt token generator to simplejwt with Django Rest Auth.
I can't log in to the admin page with Django3
I compared while reading the documentation to use Jinja2 with Django
Create a REST API to operate dynamodb with the Django REST Framework
[Django] I made a field to enter the date with 4 digit numbers
I tried to save the data with discord
I wanted to play with the Bezier curve
I failed to install django with pip, so a reminder of the solution
I just wanted to extract the data of the desired date and time with Django
I tried to learn the sin function with chainer
I tried to create a table only with Django
I want to scroll the Django shift table, but ...
I tried to touch the CSV file with Python
I tried to solve the soma cube with python
Create a Todo app with the Django REST framework
When you want to filter with Django REST framework
Transit to the update screen with the Django a tag
I tried to solve the problem with Python Vol.1
I wrote you to watch the signal with Go
I also tried to imitate the function monad and State monad with a generator in Python
I tried to find the entropy of the image with python
How to write custom validations in the Django REST Framework
I tried to simulate how the infection spreads with Python
I tried to analyze the whole novel "Weathering with You" ☔️
I wanted to solve the Panasonic Programming Contest 2020 with Python
I tried to find the average of the sequence with TensorFlow
The first API to make with python Djnago REST framework
I want to make a blog editor with django admin
I want to change the Japanese flag to the Palau flag with Numpy
What I did to welcome the Python2 EOL with confidence
[Python] I want to use the -h option with argparse
I captured the Touhou Project with Deep Learning ... I wanted to.
I tried to divide the file into folders with Python
How to use the generator
Django REST framework with Vue.js
Login with django rest framework
I tried to describe the traffic in real time with WebSocket
I want to know the weather with LINE bot feat.Heroku + Python
I tried to automate the watering of the planter with Raspberry Pi
[Introduction to StyleGAN] I played with "The Life of a Man" ♬
I want to output the beginning of the next month with Python
I tried to process the image in "sketch style" with OpenCV
[Introduction to sinGAN-Tensorflow] I played with the super-resolution "Challenge Big Imayuyu" ♬
I tried to get started with Bitcoin Systre on the weekend
I wanted to solve the ABC164 A ~ D problem with Python
I tried to process the image in "pencil style" with OpenCV
I tried to expand the size of the logical volume with LVM
For the time being, I want to convert files with ffmpeg !!
I want to check the position of my face with OpenCV!
I tried to improve the efficiency of daily work with Python