Lyamaa
Posted on May 24, 2021
REST implementation of Django authentication system. djoser library provides a set of Django Rest Framework views to handle basic actions such as registration, login, logout, password reset and account activation. It works with custom user model.
Requirements:
Project Setup:
create a virtual env.
python -m venv env
Activate
./env/Scripts/activate # for windows
source env/bin/activate # linux user
Here i am using poetry you can use pip or pienv:
poetry Setup:
poetry init
poetry add django djangorestframework djoser djangorestframework_simplejwt django-cors-headers
poetry add drf-yasg # for api docs
Creating project and apps:
django-admin startproject core
python manage.py startapp accounts
Configuring settings.py:
# Installed Apps
DJANGO_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
]
PROJECT_APPS = ["accounts"]
THIRD_PARTY_APPS = [
"rest_framework",
"drf_yasg",
"djoser",
"corsheaders",
"rest_framework_simplejwt",
"rest_framework_simplejwt.token_blacklist",
]
INSTALLED_APPS = DJANGO_APPS + PROJECT_APPS + THIRD_PARTY_APPS
MIDDLEWARE = [
"django.middleware.security.SecurityMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
"corsheaders.middleware.CorsMiddleware", # middleware for cors-headers
"django.middleware.common.CommonMiddleware",
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
]
let's create a custom user model:
accounts/models.py
from django.db import models
from django.contrib.auth.models import (
AbstractBaseUser,
PermissionsMixin,
BaseUserManager,
)
class CustomUserManager(BaseUserManager):
def create_user(self, email, username, password=None, **extra_fields):
if not email:
raise ValueError("User must have an email")
email = self.normalize_email(email)
user = self.model(email=email, username=username, **extra_fields)
user.set_password(password)
user.save(using=self._db)
return user
def create_superuser(self, username, email, password=None, **extra_fields):
user = self.create_user(username, email, password=password, **extra_fields)
user.is_active = True
user.is_staff = True
user.is_admin = True
user.save(using=self._db)
return user
class CustomUser(AbstractBaseUser, PermissionsMixin):
email = models.EmailField(max_length=255, unique=True)
username = models.CharField(max_length=255, unique=True)
first_name = models.CharField(max_length=255)
last_name = models.CharField(max_length=255)
is_active = models.BooleanField(default=True)
is_staff = models.BooleanField(default=False)
is_admin = models.BooleanField(default=False)
objects = CustomUserManager()
USERNAME_FIELD = "email"
REQUIRED_FIELDS = ["username", "first_name", "last_name"]
def get_full_name(self):
return f"{self.first_name} - {self.last_name}"
def get_short_name(self):
return self.username
def has_perm(self, perm, obj=None):
return True
def has_module_perms(self, app_label):
return True
def __str__(self):
return self.email
Customizing Serializers
accounts/serializers.py
from djoser.serializers import UserCreateSerializer
from django.contrib.auth import get_user_model
User = get_user_model()
class UserCreateSerializer(UserCreateSerializer):
class Meta(UserCreateSerializer.Meta):
model = User
fields = ("id", "email", "username", "first_name", "last_name", "password")
Email setup: settings.py
# EMAIL CONFIG
EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
EMAIL_HOST = "localhost"
EMAIL_PORT = "1025"
EMAIL_HOST_USER = ""
EMAIL_HOST_PASSWORD = ""
EMAIL_USE_TLS = False
Djoser JWT and CORS HEADERS: settings.py
[Note: you won't need cors header unless you use any frontend framework or libraries]
REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": ["rest_framework.permissions.IsAuthenticated"],
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
}
SIMPLE_JWT = {
"AUTH_HEADER_TYPES": ("JWT",),
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
}
# DJOSER CONFIG
DJOSER = {
"LOGIN_FIELD": "email",
"USER_CREATE_PASSWORD_RETYPE": True,
"USERNAME_CHANGED_EMAIL_CONFIRMATION": True,
"PASSWORD_CHANGED_EMAIL_CONFIRMATION": True,
"SEND_CONFIRMATION_EMAIL": True,
"SET_USERNAME_RETYPE": True,
"SET_PASSWORD_RETYPE": True,
"USERNAME_RESET_CONFIRM_URL": "password/reset/confirm/{uid}/{token}",
"PASSWORD_RESET_CONFIRM_URL": "email/reset/confirm/{uid}/{token}",
"ACTIVATION_URL": "activate/{uid}/{token}",
"SEND_ACTIVATION_EMAIL": True,
"SOCIAL_AUTH_TOKEN_STRATEGY": "djoser.social.token.jwt.TokenStrategy",
"SOCIAL_AUTH_ALLOWED_REDIRECT_URIS": [
"your redirect url",
"your redirect url",
],
"SERIALIZERS": {
"user_create": "accounts.serializers.UserCreateSerializer", # custom serializer
"user": "djoser.serializers.UserSerializer",
"current_user": "djoser.serializers.UserSerializer",
"user_delete": "djoser.serializers.UserSerializer",
},
}
# CORS HEADERS
CORS_ORIGIN_ALLOW_ALL = True
CORS_ALLOW_CREDENTIALS = True
URL CONFIG:
- accounts/urls.py
from django.urls import path
urlpatterns = []
- main/urls.py
#main/urls.py
from django.contrib import admin
from django.urls import path
from django.urls.conf import include, re_path
# DRF YASG
from rest_framework import permissions
from drf_yasg.views import get_schema_view
from drf_yasg import openapi
schema_view = get_schema_view(
openapi.Info(
title="Djoser API",
default_version="v1",
description="REST implementation of Django authentication system. djoser library provides a set of Django Rest Framework views to handle basic actions such as registration, login, logout, password reset and account activation. It works with custom user model.",
contact=openapi.Contact(email="contact@snippets.local"),
license=openapi.License(name="BSD License"),
),
public=True,
permission_classes=(permissions.AllowAny,),
)
urlpatterns = [
path("admin/", admin.site.urls),
re_path(
r"^api/v1/docs/$",
schema_view.with_ui("swagger", cache_timeout=0),
name="schema-swagger-ui",
),
path("api/v1/", include("accounts.urls")),
path("api/v1/", include("djoser.urls")),
path("api/v1/", include("djoser.urls.jwt")),
]
Here we:
- include some url paths that djoser provides us.
- and config for API docs http://127.0.0.1:8000/api/v1/docs/
here are some urls:
- Register User http://127.0.0.1:8000/api/v1/users/
- User activation http://127.0.0.1:8000/api/v1/users/activation/
Requires two parameters:
{
"uid" :"some uid",
"token": "some token"
}
Similarly you can work with below apis.
- User login http://127.0.0.1:8000/api/v1/jwt/create/
- Reset Password http://127.0.0.1:8000/api/v1/users/reset_password/
- Reset Password Confirm http://127.0.0.1:8000/api/v1/users/reset_password_confirm/
- User Me http://127.0.0.1:8000/api/v1/users/me/
we can work with social-auth too but we require extra configs.
here is the github link where i have work with social auth
overall we are done. 😌😌😌😌
If you are stuck 👇👇👇.
Posted on May 24, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.