
Tuesday, August 4, 2020
In our previous post, we have successfully built our basic API using Django and DRF. In this post, we will add authentication and make our API Production ready. Django-allauth saves our time in writing user models entirely from scratch. Many of you won't be liking this part because most of the apps use social or phone authentication, But my intention is to do things from the start. Django rest auth turns our allauth models into JSON serializable.
Let's Install these
Django-allauth uses the username as a mandatory and unique field, I would like to overwrite that with email by Extending BaseUserManager to our CustomUserManager. We also need some extra fields to the superuser.
Add this to the Managers.py file
Let's make email as a unique identifier by subclassing AbstractUser. Here go our models file for the user.
Now its time to serialize our models using rest framework.
Update api/urls.py file. You can also extend users urls to the api urls.
If everything goes fine you can register an account and login.
navigate to http://127.0.0.1:8000/rest-auth/register/ to register
http://127.0.0.1:8000/rest-auth/login/ to login
http://127.0.0.1:8000/rest-auth/user/ to display user details
Well! Its time for jwt. Django allauth provides session key for each user, you may ask why JWT then ?. Because the structure of jwt helps us to verify who is the sender by signing it. Jwt has two tokens access and refresh token. Their name itself says what they do. The access token is short-lived (5 min or so can be customised though). The refresh token is long-lived usually expires in 24 hrs can also be customized. You need to use login credentials to refresh token to refresh.
Let's install jwt
Let's Install these
pip install django-allauth==0.42.0 django-rest-auth==0.9.5Create an app for Users
django-admin startapp usersDon't forget to add these apps to Installed Apps in api/Settings.py
Django-allauth uses the username as a mandatory and unique field, I would like to overwrite that with email by Extending BaseUserManager to our CustomUserManager. We also need some extra fields to the superuser.
Add this to the Managers.py file
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.contrib.auth.base_user import BaseUserManager | |
from django.utils.translation import ugettext_lazy as _ | |
class CustomUserManager(BaseUserManager): | |
""" | |
Custom user model manager where email is the unique identifiers | |
for authentication instead of usernames. | |
""" | |
def create_user(self, email, password, **extra_fields): | |
""" | |
Create and save a User with the given email and password. | |
""" | |
if not email: | |
raise ValueError(_('The Email must be set')) | |
email = self.normalize_email(email) | |
user = self.model(email=email, **extra_fields) | |
user.set_password(password) | |
user.save() | |
return user | |
def create_superuser(self, email, password, **extra_fields): | |
""" | |
Create and save a SuperUser with the given email and password. | |
""" | |
extra_fields.setdefault('is_staff', True) | |
extra_fields.setdefault('is_superuser', True) | |
extra_fields.setdefault('is_active', True) | |
if extra_fields.get('is_staff') is not True: | |
raise ValueError(_('Superuser must have is_staff=True.')) | |
if extra_fields.get('is_superuser') is not True: | |
raise ValueError(_('Superuser must have is_superuser=True.')) | |
return self.create_user(email, password, **extra_fields) |
Let's make email as a unique identifier by subclassing AbstractUser. Here go our models file for the user.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from django.db import models | |
# Create your models here. | |
from django.contrib.auth.models import AbstractUser | |
from django.utils.translation import ugettext_lazy as _ | |
from .managers import CustomUserManager | |
class CustomUser(AbstractUser): | |
username = None | |
email = models.EmailField(_('email address'), unique=True) | |
USERNAME_FIELD = 'email' | |
REQUIRED_FIELDS = [] | |
objects = CustomUserManager() | |
profile_name = models.CharField(blank=True, max_length=100) | |
avatar = models.ImageField(upload_to='avatars/', null=True, blank=True) | |
def set_avatar(self): | |
avatar = self.avatar | |
if not avatar: | |
self.avatar="------REPLACE THIS WITH YOUR DEFAULT AVATAR URL-----" | |
def __str__(self): | |
return self.email |
Now its time to serialize our models using rest framework.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from rest_framework import serializers | |
from users.models import CustomUser | |
class UserSerializer(serializers.ModelSerializer): | |
class Meta: | |
model = CustomUser | |
fields = ['id', 'email', 'profile_name', 'avatar',] |
Update api/urls.py file. You can also extend users urls to the api urls.
from django.conf.urls import url
from django.conf import settings
from allauth.account.views import confirm_email
url(r'^rest-auth/', include('rest_auth.urls')),
url(r'^rest-auth/registration/', include('rest_auth.registration.urls')),
url(r'^account/', include('allauth.urls')),
url(r'^accounts-rest/registration/account-confirm-email/(?P<key>.+)/$', confirm_email, name='account_confirm_email'),
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#Now add this to api/settings.py | |
AUTH_USER_MODEL = 'users.CustomUser' | |
ACCOUNT_USER_MODEL_USERNAME_FIELD = None | |
#setting email field as required one | |
ACCOUNT_EMAIL_REQUIRED = True | |
ACCOUNT_UNIQUE_EMAIL = True | |
ACCOUNT_USERNAME_REQUIRED = False | |
ACCOUNT_AUTHENTICATION_METHOD = 'email' | |
#change optional to mandatory to mandate email verification. | |
ACCOUNT_EMAIL_VERIFICATION = 'optional' | |
ACCOUNT_CONFIRM_EMAIL_ON_GET = True | |
#Change these to set custom page to redirect user after email verification. | |
ACCOUNT_EMAIL_CONFIRMATION_ANONYMOUS_REDIRECT_URL = '/' | |
ACCOUNT_EMAIL_CONFIRMATION_AUTHENTICATED_REDIRECT_URL = '/ | |
SITE_ID = 1 | |
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' | |
AUTHENTICATION_BACKENDS = ( | |
# default | |
'django.contrib.auth.backends.ModelBackend', | |
# email login | |
'allauth.account.auth_backends.AuthenticationBackend', | |
) |
If everything goes fine you can register an account and login.
navigate to http://127.0.0.1:8000/rest-auth/register/ to register
http://127.0.0.1:8000/rest-auth/login/ to login
http://127.0.0.1:8000/rest-auth/user/ to display user details
Well! Its time for jwt. Django allauth provides session key for each user, you may ask why JWT then ?. Because the structure of jwt helps us to verify who is the sender by signing it. Jwt has two tokens access and refresh token. Their name itself says what they do. The access token is short-lived (5 min or so can be customised though). The refresh token is long-lived usually expires in 24 hrs can also be customized. You need to use login credentials to refresh token to refresh.
Let's install jwt
pip install djangorestframework-jwt==1.11.0after installing navigate to API and edit settings.py and add this
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
REST_FRAMEWORK = { | |
'DEFAULT_PERMISSION_CLASSES': ( | |
# By default we set everything to admin, | |
# then open endpoints on a case-by-case basis | |
'rest_framework.permissions.IsAdminUser', | |
), | |
'TEST_REQUEST_RENDERER_CLASSES': ( | |
'rest_framework.renderers.MultiPartRenderer', | |
'rest_framework.renderers.JSONRenderer', | |
'rest_framework.renderers.TemplateHTMLRenderer' | |
), | |
'DEFAULT_AUTHENTICATION_CLASSES': ( | |
'rest_framework_jwt.authentication.JSONWebTokenAuthentication', | |
'rest_framework.authentication.SessionAuthentication', | |
), | |
#sets the pagination to the API endpoint | |
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', | |
'PAGE_SIZE': 20, | |
} | |
from datetime import timedelta | |
JWT_AUTH = { | |
'JWT_ALLOW_REFRESH': True, | |
'JWT_EXPIRATION_DELTA': timedelta(hours=1), | |
#expires in 1 day you can change according to your needs | |
'JWT_REFRESH_EXPIRATION_DELTA': timedelta(days=1), | |
} |
Now add these to api/urls.py
Now uncomment the line permission_classes = (permissions.IsAuthenticated,) in music views as we have discussed in the previous post, this allows only authenticated users to
access the music files.
Finally! we have successfully built our backend using Django, DRF, JWT.In the next post, we will parse the api and play music files for authenticated users using vuejs. PART 3
You can access the entire backend which can be hosted on Heroku. Ronix-backend
Have a good day!
url(r'^api/v1/auth/obtain_token/', obtain_jwt_token),Navigate to http://127.0.0.1:8000/api/v1/auth/obtain_token/ to obtain the token.
url(r'^api/v1/auth/refresh_token/', refresh_jwt_token),
Now uncomment the line permission_classes = (permissions.IsAuthenticated,) in music views as we have discussed in the previous post, this allows only authenticated users to
access the music files.
Finally! we have successfully built our backend using Django, DRF, JWT.
You can access the entire backend which can be hosted on Heroku. Ronix-backend
Have a good day!
Tuesday, August 4, 2020
Nodejs
python
web development
0 Response to Django + vuejs + Django rest framework and jwt - Part 2
Comments are personally moderated by our team. Promotions are not encouraged.
Post a Comment