CBi analytics login register

Requirements backend

Django
Djangorestframework
Django-cors-headers
Knox
Cryptography
Boto3
Django_rest_passwordreset
Django-rest-knox

Backend

Create folder called backend

Cd backend

Python -m pip install virtualenv  

Python -m venv venv 
Creates virtual environment called venv

venv/scripts/activate

Its worth gitignor-ing your virtual environment

pip install Django djangorestframework django-cors-headers knox cryptography Jinja2 boto3 django-rest-passwordreset django-rest-knox
Django-admin startproject auth .

Not nested folder

Python manage.py startapp users

Add these to install apps in auth/settings .py

'rest_framework',
    'corsheaders',
    'users',
    'knox',
    'django_rest_passwordreset',

Add this to top of middleware

'corsheaders.middleware.CorsMiddleware',

Add allowed origins just below middleware

CORS_ALLOWED_ORIGINS = [
 'http://localhost:5173',
]

Add this line just below that line

AUTH_USER_MODEL = 'users.CustomUser'

Just below that add this line

AUTHENTICATION_BACKENDS = [
    # 'users.authback.EmailBackend',
    "django.contrib.auth.backends.ModelBackend", # this line fixed my problem
]

Use these lines for the email settings

#the email settings
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = os.environ.get('EMAIL_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_PASSWORD')
DEFAULT_FROM_EMAIL = 'CBI ANALYTICS'
# Internationalization
# https://docs.djangoproject.com/en/4.2/topics/i18n/

Make sure templates is correct

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [BASE_DIR/"templates"],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

Configure authentication classes

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': ('knox.auth.TokenAuthentication',)
}

Then update urls.py

from django.contrib import admin
from django.urls import path, include
from knox import views as knox_views


urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('users.urls')),
    #path('api/auth/',include('knox.urls')),


    path('logout/',knox_views.LogoutView.as_view(), name='knox_logout'),
    path('logoutall/',knox_views.LogoutAllView.as_view(), name='knox_logoutall'),
    path('api/password_reset/',include('django_rest_passwordreset.urls', namespace='password_reset')),


]

In users app add this code to models.py

from django.db import models
from django.contrib.auth.models import AbstractUser
from django.contrib.auth.base_user import BaseUserManager


from django_rest_passwordreset.signals import reset_password_token_created
from django.dispatch import receiver
from django.urls import reverse
from django.template.loader import render_to_string
from django.core.mail import EmailMultiAlternatives
from django.utils.html import strip_tags


class CustomUserManager(BaseUserManager):
    def create_user(self, email, password=None, **extra_fields ):
        if not email:
            raise ValueError('Email is a required field')

        email = self.normalize_email(email)
        user = self.model(email=email, **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user


    def create_superuser(self,email, password=None, **extra_fields):
        extra_fields.setdefault('is_staff', True)
        extra_fields.setdefault('is_superuser', True)
        return self.create_user(email, password, **extra_fields)


class CustomUser(AbstractUser):
    email = models.EmailField(max_length=200, unique=True)
    birthday = models.DateField(null=True, blank=True)
    username = models.CharField(max_length=200, null=True, blank=True)


    objects = CustomUserManager()


    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []




@receiver(reset_password_token_created)
def password_reset_token_created(reset_password_token, *args, **kwargs):
    sitelink = "http://localhost:5173/"
    token = "{}".format(reset_password_token.key)
    full_link = str(sitelink)+str("password-reset/")+str(token)


    print(token)
    print(full_link)


    context = {
        'full_link': full_link,
        'email_adress': reset_password_token.user.email
    }


    html_message = render_to_string("backend/email.html", context=context)
    plain_message = strip_tags(html_message)


    msg = EmailMultiAlternatives(
        subject = "Request for resetting password for {title}".format(title=reset_password_token.user.email),
        body=plain_message,
        from_email = "[email protected]",
        to=[reset_password_token.user.email]
    )


    msg.attach_alternative(html_message, "text/html")
    msg.send()

Also add this code to views.py

from django.shortcuts import render
from rest_framework import viewsets, permissions
from .serializers import *
from .models import *
from rest_framework.response import Response
from django.contrib.auth import get_user_model, authenticate
from knox.models import AuthToken


User = get_user_model()


class LoginViewset(viewsets.ViewSet):
    permission_classes = [permissions.AllowAny]
    serializer_class = LoginSerializer


    def create(self, request):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            email = serializer.validated_data['email']
            password = serializer.validated_data['password']
            user = authenticate(request, email=email, password=password)
            if user:
                _, token = AuthToken.objects.create(user)
                return Response(
                    {
                        "user": self.serializer_class(user).data,
                        "token": token
                    }
                )
            else:
                return Response({"error":"Invalid credentials"}, status=401)    
        else:
            return Response(serializer.errors,status=400)






class RegisterViewset(viewsets.ViewSet):
    permission_classes = [permissions.AllowAny]
    queryset = User.objects.all()
    serializer_class = RegisterSerializer


    def create(self,request):
        serializer = self.serializer_class(data=request.data)
        if serializer.is_valid():
            serializer.save()
            return Response(serializer.data)
        else:
            return Response(serializer.errors,status=400)




class UserViewset(viewsets.ViewSet):
    permission_classes = [permissions.IsAuthenticated]
    queryset = User.objects.all()
    serializer_class = RegisterSerializer


    def list(self,request):
        queryset = User.objects.all()
        serializer = self.serializer_class(queryset, many=True)
        return Response(serializer.data)

Create a urls.py file and add this code

from django.contrib import admin
from django.urls import path
from rest_framework.routers import DefaultRouter
from .views import *


router = DefaultRouter()
router.register('register', RegisterViewset, basename='register')
router.register('login', LoginViewset, basename='login')
router.register('users', UserViewset, basename='users')
urlpatterns = router.urls

Create a serializers.py file and add this code

from rest_framework import serializers
from .models import *
from django.contrib.auth import get_user_model
User = get_user_model()


class LoginSerializer(serializers.Serializer):
    email = serializers.EmailField()
    password = serializers.CharField()


    def to_representation(self, instance):
        ret = super().to_representation(instance)
        ret.pop('password', None)
        return ret




class RegisterSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('id','email','password')
        extra_kwargs = { 'password': {'write_only':True}}

    def create(self, validated_data):
        user = User.objects.create_user(**validated_data)
        return user

Create auth_backend.py file and add this code

from django.contrib.auth import get_user_model
User = get_user_model()


class EmailAuthBackend:
    def authenticate(self, request, email=None, password=None):
        try:
            user = User.objects.get(email=email)
            if user.check_password(password):
                return user
        except User.DoesNotExist:
            return None

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None

In the terminal do python manage.py makemigrations and then python manage.py migrate

Run the server
Python manage.py runserver and run some post requests
We are now finished with the backend

from django.contrib.auth import get_user_model
User = get_user_model()

class EmailAuthBackend:
def authenticate(self, request, email=None, password=None):
try:
user = User.objects.get(email=email)
if user.check_password(password):
return user
except User.DoesNotExist:
return None

def get_user(self, user_id):
    try:
        return User.objects.get(pk=user_id)
    except User.DoesNotExist:
        return None

Add this to apps.py file

from django.apps import AppConfig

class UsersConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'users'

Make sure admin.py looks like this

from django.contrib import admin
from .models import *

Register your models here.

admin.site.register(CustomUser)

In the terminal do python manage.py makemigrations and then python manage.py migrate

Run the server
Python manage.py runserver and run some post requests
We are now finished with the backend