DEV Community

Cover image for FullStack React & Django Authentication : Django REST ,TypeScript, Axios, Redux & React Router

FullStack React & Django Authentication : Django REST ,TypeScript, Axios, Redux & React Router

Mangabo Kolawole on June 27, 2021

As a full-stack developer, understand how to build an authentication system with backend technology and manage the authentication flow with a front...
Collapse
 
okechedu profile image
Edward Okech

@koladev I have also realised that when running the command
$ yarn start after adding the craco.config.js file the following error is thrown

PS C:\Users\Administrator\Documents\EdwardFiles\Python\django_projects\Zetech-Uni-Portal\frontend> yarn start
yarn run v1.22.19
warning ..\..\..\..\..\..\package.json: No license field
$ craco start
C:\Users\Administrator\Documents\EdwardFiles\Python\django_projects\Zetech-Uni-Portal\frontend\node_modules\@craco\craco\lib\features\webpack\style\postcss.js:54
                craPlugins = match.loader.options.plugins();
                                                  ^

TypeError: match.loader.options.plugins is not a function

Enter fullscreen mode Exit fullscreen mode

After a bit of digging i found this article
github.com/facebook/create-react-a...

basicly replacing the following line in the croca.config.js file solves this issue.

module.exports = {
    style: {
       // Replace postcss with postcssOptions
        postcssOptions: {
        plugins: [require("tailwindcss"), require("autoprefixer")],
      },
    },
  };
Enter fullscreen mode Exit fullscreen mode

Thank you

Collapse
 
okechedu profile image
Edward Okech

@Mangabo Thanks for this amazing and insightful article I have learnt alot. However, i can't figure out why i can't login superusers in Django admin..getting an alert of
"
Please enter the correct email and password for a staff account. Note that both fields may be case-sensitive.
"
On terminal the following message is returned from the server

django.core.management.base.SystemCheckError: SystemCheckError: System check identified some issues:

ERRORS:
auth.User.groups: (fields.E304) Reverse accessor for 'auth.User.groups' clashes with reverse accessor for 'core_user.User.groups'.
        HINT: Add or change a related_name argument to the definition for 'auth.User.groups' or 'core_user.User.groups'.
auth.User.user_permissions: (fields.E304) Reverse accessor for 'auth.User.user_permissions' clashes with reverse accessor for 'core_user.User.user_permissions'.
        HINT: Add or change a related_name argument to the definition for 'auth.User.user_permissions' or 'core_user.User.user_permissions'.
core_user.User.groups: (fields.E304) Reverse accessor for 'core_user.User.groups' clashes with reverse accessor for 'auth.User.groups'.
        HINT: Add or change a related_name argument to the definition for 'core_user.User.groups' or 'auth.User.groups'.
core_user.User.user_permissions: (fields.E304) Reverse accessor for 'core_user.User.user_permissions' clashes with reverse accessor for 'auth.User.user_permissions'.
        HINT: Add or change a related_name argument to the definition for 'core_user.User.user_permissions' or 'auth.User.user_permissions'.
Enter fullscreen mode Exit fullscreen mode

Kindly any one with an idea of what might be the issue?

Collapse
 
koladev profile image
Mangabo Kolawole

Hi Edward. Thank you very much for your feedback. Let me try the code and come back to you.

Collapse
 
koladev profile image
Mangabo Kolawole • Edited

Interestingly, I cloned the source code from Github and setup the project. I can actually connect in the admin dashboard, but with my email, and not the username.

I think that I created this confusion tho as I only wanted the user to connect with the email.

In the User model, you can set these attributes so any user can connect with username and email.

class User(AbstractBaseUser, PermissionsMixin):
    ...

    USERNAME_FIELD = 'username'
    EMAIL_FIELD = 'email'

    objects = UserManager()

    def __str__(self):
        return f"{self.email}"
Enter fullscreen mode Exit fullscreen mode

Please, let me know if it works.

Thread Thread
 
okechedu profile image
Edward Okech

Hi Mangambo, i made the changes. However was still facing the same issue. I decided to change the Model as of below and it worked.

import uuid
from enum import unique
from django.db import models
from django.conf import settings
from django.utils import timezone
from django.core.mail import send_mail
from django.core.validators import RegexValidator
from dateutil.relativedelta import relativedelta
from django.utils.translation import gettext_lazy as _
from phonenumber_field.modelfields import PhoneNumberField
from django.contrib.auth.models import AbstractBaseUser, PermissionsMixin, BaseUserManager


def two_days_from_now():
    # A helper function to deactivate email activation link after 2 days
    return timezone.now() + relativedelta(days=2)


class UserManager(BaseUserManager):
    """
    We use Django's inbuilt BaseUserManager Class
    """
    def _create_user(self, username, email, password, is_staff, is_superuser, **extra_fields):
        """
        Creates and saves a User with the given email and password.
        """
        now = timezone.now()
        if not email:
            raise ValueError('Users must have an email address')
        if not username:
            raise ValueError('Users must have a username')
        email = self.normalize_email(email)
        user = self.model(username=username,
                          email=email,
                          is_staff=is_staff, 
                          is_active=True,
                          is_superuser=is_superuser, 
                          last_login=now,
                          date_joined=now, 
                          **extra_fields)
        user.set_password(password)
        user.save(using=self._db)
        return user

    def create_user(self, username, email, password=None, **extra_fields):
        return self._create_user(username, email, password, False, False, **extra_fields)

    def create_superuser(self, username, email, password, **extra_fields):
        return self._create_user(username, email, password, True, True, **extra_fields)


class User(AbstractBaseUser, PermissionsMixin):
    # The base Zetech user's model fields
    alphanumeric = RegexValidator(r'^[0-9a-zA-Z]*$', message='Only alphanumeric characters are allowed.')

    ### Redefine the basic fields that would normally be defined in User ###
    username = models.CharField(unique=True, max_length=20, validators=[alphanumeric])
    email = models.EmailField(verbose_name='email address', unique=True, max_length=255)
    first_name = models.CharField(max_length=30, null=True, blank=True)
    last_name = models.CharField(max_length=50, null=True, blank=True)
    date_joined = models.DateTimeField(auto_now_add=True)
    is_active = models.BooleanField(default=True, 
                                    null=False, 
                                    help_text=_('Designates whether this user should be treated as active. Unselect this instead of deleting accounts.'))
    is_staff = models.BooleanField(default=False, 
                                   null=False, 
                                   help_text=_('Designates whether the user can log into this admin site.'))

    ### NOTE: is_superuser is not defined here. This is because PermissionsMixin already defines this, and if you override it,
    ### then all the default Django user permissions won't work correctly, so you have to make sure you don't override the
    ### is_superuser field.

    ### Our own fields - we shall use this for the user account profile ###
    phone_number = PhoneNumberField()
    profile_image = models.ImageField(upload_to="uploads", blank=False, null=False, default="/static/images/defaultuserimage.png")
    user_bio = models.CharField(max_length=600, blank=True)
    is_uni_staff = models.BooleanField(default=False,
                                     null=False,
                                     help_text=_('Designates whether user is a staff of the university'))
    is_student = models.BooleanField(default=False,
                                    null=False,
                                     help_text=_('Designates whether user is a student in the university'))

    objects = UserManager()
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    class Meta:
        verbose_name = 'User'
        verbose_name_plural = 'Users'

    def get_full_name(self):
        fullname = "{first_name} {last_name}".format(first_name=self.first_name, last_name=self.last_name)
        return fullname

    def get_short_name(self):
        return self.username

    def __str__(self):
        return "{0} ({1})".format(self.username, self.email)

    def email_user(self, subject, message, from_email=None):
        """
        Sends an email to this User.
        """
        send_mail(subject, message, from_email, [self.email])



class Registration(models.Model):
    uuid = models.UUIDField(primary_key=False, default=uuid.uuid4, editable=False)
    user = models.OneToOneField(User, related_name='registration', on_delete=models.CASCADE)
    expires = models.DateTimeField(default=two_days_from_now)
    type = models.CharField(max_length=10, choices=(
      ('register', 'register'),
      ('lostpass', 'lostpass'),
    ), default = 'register')
Enter fullscreen mode Exit fullscreen mode

Thanks for the article.

Collapse
 
ktoole profile image
Kristian Toole

Thanks for this awesome tutorial!! Is there a way to make the auth/register only available to super users? That way if the app is public facing, not just anyone can create themselves as a user. Any tips or advice for this?

Collapse
 
ktoole profile image
Kristian Toole

I think I just now figured it out. I updated the permission_classes for the registrationviewset. :)

Collapse
 
anjayluh profile image
Angella Naigaga • Edited

Thank you for coming up with this tutorials.
I am getting myself familiar with django so I landed on this tutorial to help me.
While following it, I encountered a couple of errors that i will mention here

  1. class RefreshViewSet(viewsets.ViewSet, TokenRefreshView):

There are two undefined vars here

  1. Add rest_framework_simplejwt.authentication.JWTAuthentication to the list of authentication classes in settings.py:

For my version of the app (I guess the recent django versions), the REST_FRAMEWORK object doesn't come included in settings.py. I had to add it myself

  1. If everything is working fine, let's create a user with an HTTP Client by requesting localhost:8000/api/auth/register/.

Here I ran into this error.
"""
ImproperlyConfigured at /api/auth/register/
Field name public_id is not valid for model User.
Request Method: POST
Request URL: localhost:8000/api/auth/register/
Django Version: 3.2.5
Exception Type: ImproperlyConfigured
Exception Value:

Field name public_id is not valid for model User.
Exception Location: /Users/anaconda3/lib/python3.8/site-packages/rest_framework/serializers.py, line 1317, in build_unknown_field
Python Executable: /Users/angellanaigaga/opt/anaconda3/bin/python
Python Version: 3.8.8
"""
My guess is it's coming from the serializers. At the point of writing this I am not sure how best to fix this bug, whether to rename public_id to id or remove it completely.

Otherwise, I appreciate the work well done

Collapse
 
anjayluh profile image
Angella Naigaga

Update
Renaming public_id to id fixes the last bug mentioned here

Collapse
 
koladev profile image
Mangabo Kolawole

Oh thanks Angella. I'll modify it

Collapse
 
koladev profile image
Mangabo Kolawole

typo fixed. Thanks again.

Collapse
 
michaeldbrant profile image
Michael Brant

Thanks for the guide! Is anyone else getting a “CSRF cookie not set” error? I tried putting @csrf_exempt as a decorator above the create method in the RegistrationViewSet but that didn’t fix it.

Collapse
 
zvolsky profile image
Zvolský

With Django/Vue/Axios I have such something in Axios settings:
axios.defaults.withCredentials = true
axios.defaults.xsrfHeaderName = "X-CSRFTOKEN"
axios.defaults.xsrfCookieName = "csrftoken"

Collapse
 
koladev profile image
Mangabo Kolawole

Hey Michael!

What's your CORS configuration? And are you using React?

Collapse
 
michaeldbrant profile image
Michael Brant

Hey! Yup, I’m using React, testing in the browser and in Postman. I’m running on port 8000 so I have :
CORS_ALLOWED_ORIGINS = [“127.0.0.1:8000”,
localhost:8000”]

CORS_ALLOW_HEADERS = [‘Accept’, ‘Accept-Language’, ‘Authorization’, ‘Content-Type’]

CORS_ALLOW_METHODS = [‘GET’, ‘POST’, ‘PUT’]

Collapse
 
wisdomtohe profile image
Wisdom TOHE

Awesome! Thank you!

Collapse
 
koladev profile image
Mangabo Kolawole

You are welcome mate

Collapse
 
karan_s_mittal profile image
Karan Mittal

It was an amazing and very well written article. Looking forward for more content from you.

Collapse
 
koladev profile image
Mangabo Kolawole

Thanks Karan.

For sure, more content are coming.

Collapse
 
muzammilaalpha profile image
muzammilaalpha

Good one!

Collapse
 
koladev profile image
Mangabo Kolawole

Thanks

Collapse
 
sm0ke profile image
Sm0ke

Nice .. 🚀🚀

Collapse
 
koladev profile image
Mangabo Kolawole

Thanks Sm0ke 🤓

Collapse
 
lcfd profile image
Luca Fedrizzi

Awesome!

Collapse
 
koladev profile image
Mangabo Kolawole

Thank you Luca!

Collapse
 
mostafaatefmohamed profile image
Mostafa Atef

I Want the HTTPS link to git clone Please ...

Collapse
 
perfectdev95 profile image
perfectdev95

Did you run this project?

Collapse
 
urekd profile image
urek-d

hi Thank you very much for your feedback i got an error when i was building de react app
Image description

Collapse
 
fancydeveloper profile image
fancydev

Thanks, very helpful tutorial.

Collapse
 
perfectdev95 profile image
perfectdev95

I download this project from github.
But I can't run.
Please help me