how-to authentication   0   524
Creating custom user model  and custom authentication in Django

While working on some django project you might feel that the default user model is not fulfilling all the requirements.

For example you may want to authenticate users by email Id and not by username. You may want to store some more extra information in the user model. In short you might want to define your own custom user model.

In particular we may encounter one out of below two scenarios:

  • You are happy with the way default authentication but you need to store extra information in the model itself.
  • You want different authentication process, for example using email, but do not want to store extra information.


We will discuss second approach here. Our approach will use custom defined user model and custom define backend authentication mechanism.


How to create a custom user model:

First of all create the user model class in your models directory. Add the usermanager class also.

from django.db import models
from django.contrib.auth.models import AbstractBaseUser, BaseUserManager


class MyUserManager(BaseUserManager):
    use_in_migrations = True
    
    # python manage.py createsuperuser
    def create_superuser(self, email, is_staff, password):
        user = self.model(
                          email = email,                         
                          is_staff = is_staff,
                          )
        user.set_password(password)
        user.save(using=self._db)
        return user

class UserModel(AbstractBaseUser):
    sys_id = models.AutoField(primary_key=True, blank=True)        
    email = models.EmailField(max_length=127, unique=True, null=False, blank=False)
    is_staff = models.BooleanField()
    is_active = models.BooleanField(default=True)
    
    objects = MyUserManager()

    USERNAME_FIELD = "email"
    # REQUIRED_FIELDS must contain all required fields on your User model, 
    # but should not contain the USERNAME_FIELD or password as these fields will always be prompted for.
    REQUIRED_FIELDS = ['is_staff']

    class Meta:
        app_label = "accounts"
        db_table = "users"

    def __str__(self):
        return self.email

    def get_full_name(self):
        return self.email

    def get_short_name(self):
        return self.email


    # this methods are require to login super user from admin panel
    def has_perm(self, perm, obj=None):
        return self.is_staff

    # this methods are require to login super user from admin panel
    def has_module_perms(self, app_label):
        return self.is_staff


Since I don't require anything except email, password, is_active and  is_staff, I removed everything else from the model.

Is_staff is required for user login in admin panel. If you are not going to use admin site then is_staff can be removed as well.

Define this newly created custom user model in settings file. Project should know that we are going to use other than default user model.

AUTH_USER_MODEL = 'accounts.UserModel'
AUTHENTICATION_BACKENDS = ('accounts.backends.MyAuthBackend','django.contrib.auth.backends.ModelBackend',)

 
As shown in code above, mention the name of custom authentication backend we will create to support our custom user model.

AUTHENTICATION_BACKENDS  is list of backends. If first one fails to authenticate, second is used as fallback. Here first authentication backend in the list is the one we will create and second is the django's default authentication backend.

Create the custom authentication backend.


backends.py :

from accounts.models import UserModel
import logging


class MyAuthBackend(object):
    def authenticate(self, email, password):    
        try:
            user = UserModel.objects.get(email=email)
            if user.check_password(password):
                return user
            else:
                return None
        except UserModel.DoesNotExist:
            logging.getLogger("error_logger").error("user with login %s does not exists " % login)
            return None
        except Exception as e:
            logging.getLogger("error_logger").error(repr(e))
            return None

    def get_user(self, user_id):
        try:
            user = UserModel.objects.get(sys_id=user_id)
            if user.is_active:
                return user
            return None
        except UserModel.DoesNotExist:
            logging.getLogger("error_logger").error("user with %(user_id)d not found")
            return None

 

Now run makemigrations and migrations command. This will create the custom user model in database. (Assuming database settings are ok).

$ python manage.py makemigrations
$ python manage.py migrate


Now create a super user. is_staff should be true for this user.

$ python manage.py createsuperuser

Running this command will ask you email id, is_staff, password and confirm password.

After user is created successfully, go to admin login and confirm if you are able to login.


If you are getting error Please enter the correct email and password for a staff account. Note that both fields may be case-sensitive , make sure you have is_staff field in model and has_perm and pas_module_perm methods define and they return true.

If you are able to login successfully, Good.


How to Register Custom user model with Admin Site:

In the above section, we created custom user model with them help of AbstractBaseUser . Custom user models created by this method are not registered normally with admin site. For this we need to override django's default UserAdmin .

In the app directory, create a file admin.py  if file do not exists already.

from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField

from accounts.models import UserModel


class UserCreationForm(forms.ModelForm):
    #A form for creating new users. Includes all the required
    #fields, plus a repeated password.
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = UserModel
        fields = ('email')

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise forms.ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super(UserCreationForm, self).save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user


class UserChangeForm(forms.ModelForm):
    #A form for updating users. Includes all the fields on
    #the user, but replaces the password field with admin's
    #password hash display field.
    
    password = ReadOnlyPasswordHashField()

    class Meta:
        model = UserModel
        fields = ('email', 'password', 'is_active','is_staff')

    def clean_password(self):
        # Regardless of what the user provides, return the initial value.
        # This is done here, rather than on the field, because the
        # field does not have access to the initial value
        return self.initial["password"]


class UserAdmin(BaseUserAdmin):
    # The forms to add and change user instances
    form = UserChangeForm
    add_form = UserCreationForm

    # The fields to be used in displaying the User model.
    # These override the definitions on the base UserAdmin
    # that reference specific fields on auth.User.
    list_display = ('email', 'is_active', 'is_staff')
    list_filter = ('email',)
    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Permissions', {'fields': ('is_staff',)}),
    )
    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email','password1', 'password2')}
        ),
    )
    search_fields = ('email',)
    ordering = ('email',)
    filter_horizontal = ()

# Now register the new UserAdmin...
admin.site.register(UserModel, UserAdmin)
# ... and, since we're not using Django's built-in permissions,
# unregister the Group model from admin.
admin.site.unregister(Group)



 Adequate comments are used in above code to make is easy to understand.

Now restart the server and login to admin site. You will be able to see the users model and you will be able to add, edit and delete the model objects.

Let me know in case of any question.  

References: https://docs.djangoproject.com/en/1.10/topics/auth/customizing/

how-to authentication   0   524

Related Articles:
Python Script 3: Validate, format and Beautify JSON string Using Python
Validating json using python code, format and beautify json file using python, validate json file using python, how to validate, format and beautify json...
Encryption-Decryption in Python Django
How to encrypt and decrypt the content in DJango. Encrypting the critical information in Django App. Encrypting username, email and password in Django...
Adding Robots.txt file to Django Application
Adding robots.txt file in your Django application. Easiest way to add robots.txt file. Django application robots.txt file. Why should you add robots.txt file in your Django Application....
How to upgrade to paid account on PythonAnyWhere
Which is the best server for hosting Django Apps. Best hosting provider for Django Apps. Cheapest Django Hosting. PythonAnyWhere Reviews. Django Hosting....

0 thoughts on 'Creating Custom User Model And Custom Authentication In Django'
Leave a comment:


*All Fields are mandatory. **Email Id will not be published publicly.


SUBSCRIBE
Please subscribe to get the latest articles in your mailbox.



Recent Posts:





© pythoncircle.com 2018-2019