User Authentication - Register & Login in Django with Simple JWT & Mysql

In the previous tutorial, you learnt to create Django APIs to perform CRUD operations on MYSQL database and tested the APIs using Django REST framework and Django Admin panel. In most cases, we need to restrict APIs access to only authenticated and authorized users. Django comes with user authentication system that help you develop your secure APIs fast.

In this tutorial, you learn to implement user authentication functionality using Django authentication system with Simple JWT that provides a JSON Web Token authorization backend. It allows user registration with username and password. In the login process, a user that provides correct username and password is authenticated and  obtains tokens (refresh and access tokens). A client app accesses restricted APIs has to provide the access token to be verified by Django backend. If the token is valid, the client app is permitted to access the APIs. 
To get started with Simple JWT, install the following dependency:

pip install djangorestframework-simplejwt

Simple JWT allows to blacklist tokens. A blacklisted token is not valid and unable to access the restricted APIs. You can make a token backlisted using Djang Admin panel. To use the blacklist functionality,  update the settings.py file to include Simple JWT blacklist.
...

INSTALLED_APPS = (
    ...
    'rest_framework_simplejwt.token_blacklist',
    ...
)
Also make sure to add the following Simple JWT configurations to the settings.py file.
....
REST_FRAMEWORK = {

    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
       
    ),
   

}
SIMPLE_JWT = {
    'ACCESS_TOKEN_LIFETIME': timedelta(days=1),
    'REFRESH_TOKEN_LIFETIME': timedelta(days=50),
    'ROTATE_REFRESH_TOKENS': True,
    'BLACKLIST_AFTER_ROTATION': True,
    'UPDATE_LAST_LOGIN': False,

    'ALGORITHM': 'HS256',

    'VERIFYING_KEY': None,
    'AUDIENCE': None,
    'ISSUER': None,
    'JWK_URL': None,
    'LEEWAY': 0,

    'AUTH_HEADER_TYPES': ('Bearer',),
    'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION',
    'USER_ID_FIELD': 'id',
    'USER_ID_CLAIM': 'user_id',
    'USER_AUTHENTICATION_RULE': 'rest_framework_simplejwt.authentication.default_user_authentication_rule',

    'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',),
    'TOKEN_TYPE_CLAIM': 'token_type',
    'TOKEN_USER_CLASS': 'rest_framework_simplejwt.models.TokenUser',

    'JTI_CLAIM': 'jti',

    'SLIDING_TOKEN_REFRESH_EXP_CLAIM': 'refresh_exp',
    'SLIDING_TOKEN_LIFETIME': timedelta(minutes=5),
    'SLIDING_TOKEN_REFRESH_LIFETIME': timedelta(days=1),
}
...

Run the following command to run app's migrations: 
python manage.py migration

Now, update jobform/serializers.py file to add RegisterSerializer and MyTokenObtainPairSerializer. The RegisterSerializer is to register a new user in Mysql database. MyTokenObtainPairSerializer helps verify username and password. Then it returns a token object if the username and password are correct.

from rest_framework import serializers
from .models import JobForm
from django.contrib.auth.models import User
from django.contrib.auth.password_validation import validate_password
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
from rest_framework.validators import UniqueValidator
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class JobFormSerializer(serializers.ModelSerializer):
    class Meta:
        model = JobForm
        fields = ('id', 'first_name', 'last_name','sex','dob','email','education','position','fileatt','user_id')


class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super().get_token(user)
        token['username'] = user.username
        token['email'] = user.email
        return token

class RegisterSerializer(serializers.ModelSerializer):
    password = serializers.CharField(
        write_only=True, required=True, validators=[validate_password])
    password2 = serializers.CharField(write_only=True, required=True)

    class Meta:
        model = User
        fields = ('username', 'password', 'password2')

    def validate(self, attrs):
        if attrs['password'] != attrs['password2']:
            raise serializers.ValidationError(
                {"password": "Password fields didn't match."})

        return attrs

    def create(self, validated_data):
        user = User.objects.create(
            username=validated_data['username']
        )

        user.set_password(validated_data['password'])
        user.save()

        return user 

Open jobform/views.py to add two more views: MyTokenObtainPaireView and RegisterView. 
The MyTokenObtainPairView class is to handle login and the RegisterView class handles registration.

from rest_framework import viewsets
from .serializers import JobFormSerializer
from .models import JobForm
from django.contrib.auth.models import User
from rest_framework_simplejwt.views import TokenObtainPairView
from .serializers import MyTokenObtainPairSerializer, RegisterSerializer
from rest_framework import generics
from rest_framework.permissions import AllowAny, IsAuthenticated
# Create your views here.
class JobFormView(viewsets.ModelViewSet):

    serializer_class = JobFormSerializer
    queryset = JobForm.objects.all()

class MyTokenObtainPairView(TokenObtainPairView):
    serializer_class = MyTokenObtainPairSerializer

class RegisterView(generics.CreateAPIView):
    permission_classes = (AllowAny,)
    queryset = User.objects.all()
    serializer_class = RegisterSerializer

Finally include the following routes to the djsite/djsite/urls.py.

......

from rest_framework_simplejwt.views import (
    TokenRefreshView,
)
......

path('login/', views.MyTokenObtainPairView.as_view(), name='token_obtain_pair'),
path('register/', views.RegisterView.as_view(), name='auth_register'),
 

Now you are ready to use the registration and login forms. Run python manage.py runserver 5000 to start development server on port 5000.To open registration form, visit http://localhost:5000/register. Input username, password, and confirm password. Then press POST to create a new user.



To open login form, visit http://localhost:5000/login. By providing correct username and password, a JSON Web Token will be returned.


To project JobFormView, you need to add permission_classes to the JobFormView class:
class JobFormView(viewsets.ModelViewSet):
    permission_classes = (IsAuthenticated,) # add this line
    serializer_class = JobFormSerializer
    queryset = JobForm.objects.all()

Save the project and then access http://localhost:5000/api/jforms. You get the following message:

To successfully access the protected view, a client app must submit a valid token.
In the next article, we will create React app to access the APIs.

Comments

Popular posts from this blog

Django - connect to Mysql database & CRUD APIs

React Django & Mysql to build a full stack job application website