Django authentication system, login,logout, sign-up, change password, reset password and customization

PAWAN THAKUR
HimachaliProgrammer
6 min readDec 29, 2017

- login, logout, signup, forget pwd, reset pwd

Today I will try to cover django authentication system. We will start our project from “Django For Real Developers — 1” onwards .

The previous project looks like this:

Final project structure of https://medium.com/himachaliprogrammer/django-for-real-developers-1-9b92e98b83f5

Prerequisites: Knowledge to class based views, as with Django 1.11 all function based auth views are deprecated. So in order to do customisation and use them we need to study them.

So now let’s start by creating new app ‘registration’.

$ ./manage.py startapp registration

make corresponding changes in main/settings.py

# settings.py
...
INSTALLED_APPS = [
'registration.apps.RegistrationConfig', #Add this
'hello.apps.HelloConfig',
'django.contrib.admin',
...

Update main/urls.py

...
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('registration.urls', namespace="accounts")), #add this line
...

Create and edit registration/urls.py

from django.urls import path
from django.contrib.auth.views import (
LoginView, LogoutView,
PasswordChangeView, PasswordChangeDoneView,
PasswordResetView,PasswordResetDoneView, PasswordResetConfirmView,PasswordResetCompleteView,
)
from .views import MySignUpView
app_name = 'registration'
urlpatterns = [
path('sign_up/', MySignUpView.as_view(), name='sign_up'),
path('login/', LoginView.as_view(), name="login"),
path('logout/', LogoutView.as_view(), name="logout"),path('password_change/', PasswordChangeView.as_view( success_url='accounts/password_change/done/'), name="password_change"),path('password_change/done/', PasswordChangeDoneView.as_view(), name="password_change_done"),path('password_reset/', PasswordResetView.as_view(success_url='done/'), name="password_reset"),path('password_reset/done/', PasswordResetDoneView.as_view(), name="password_reset_done"),path('reset/<uidb64>/<token>/', PasswordResetConfirmView.as_view( success_url='/accounts/reset/done/'), name="password_reset_confirm"),path('reset/done/', PasswordResetCompleteView.as_view(), name="password_reset_complete"),

#TODO
# path('profile/update', CustomProfileEditView.as_view(), name="update_porfile"),
]

Add required html files to registration/templates/registration/*

login.html

{% extends "base.html" %}{% block content %}
<div class="container">
<div class="row justify-content-center align-items-center" style="height:80vh;">
<div class="col-auto border p-3">
{% if form.errors %}
<p class="bg-danger p-2">Please login with your credentials.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p class="bg-warning p-1">Your account doesn't have access.</p>
{% else %}
<p class="bg-secondary">Please login to see this page.</p>
{% endif %}
{% endif %}
<form method="post" action="{% url 'accounts:login' %}">
{% csrf_token %}
<table>
<tr>
<td>{{ form.username.label_tag }} </td>
<td>{{ form.username }}</td>
</tr>
<tr>
<td>{{ form.password.label_tag }} </td>
<td>{{ form.password }}</td>
</tr>
</table>
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
{# Assumes you setup the password_reset view in your URLconf #}
<p><a href="{% url 'accounts:password_reset' %}">Lost password?</a></p>
</div>
</div>
</div>
{% endblock %}

logged_out.html

{% extends "base.html" %}{% block content %}
<div class="container">
<div class="row justify-content-center align-items-center" style="height:80vh;">
<div class="col-auto border p-3">
You are logged out
</div>
</div>
</div>
{% endblock %}

password_change_form.html

{% extends "base.html" %}{% block content %}
<div class="container">
<div class="row justify-content-center align-items-center" style="height:80vh;">
<div class="col-auto border p-3">
{% if form.errors %}
<p class="bg-danger p-2">Incorrect password</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p class="bg-warning p-1">Your account doesn't have access.</p>
{% else %}
<p class="bg-secondary">Please login to see this page.</p>
{% endif %}
{% endif %}
<form method="post" action="{% url 'accounts:password_change' %}">
{% csrf_token %}
{{ form.as_p}}
<input class="mt-3" type="submit" value="Change Password" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
</div>
</div>
</div>
{% endblock %}

password_change_done.html

{% extends "base.html" %}{% block content %}
<div class="container">
<div class="row justify-content-center align-items-center" style="height:80vh;">
<div class="col-auto border p-3">
Your password successfully has been succesffully changed
</div>
</div>
</div>
{% endblock %}

password_reset_form.html

{% extends "base.html" %}{% block content %}
<div class="container">
<div class="row justify-content-center align-items-center" style="height:80vh;">
<div class="col-auto border p-3">
{% if form.errors %}
<p class="bg-danger p-2">Incorrect email address !</p>
{% endif %}
<form method="post" action="{% url 'accounts:password_reset' %}">
{% csrf_token %}
{{ form.as_p}}
<input class="mt-3" type="submit" value="Submit" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
</div>
</div>
</div>
{% endblock %}

password_reset_email.html

Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'accounts:password_reset_confirm' uidb64=uid token=token %}

password_reset_subject.html

Password reset link

password_reset_done.html

{% extends "base.html" %}{% block content %}
<div class="container">
<div class="row justify-content-center align-items-center" style="height:80vh;">
<div class="col-auto border p-3">
Your request to reset your password is accepted! Please check your email.
</div>
</div>
</div>
{% endblock %}

password_reset_confirm.html

{% extends "base.html" %}{% block content %}
<div class="container">
<div class="row justify-content-center align-items-center" style="height:80vh;">
<div class="col-auto border p-3">
{% if form.errors %}
<p class="bg-danger p-2">New password criteria failed !</p>
{% endif %}
<form method="post" action="">
{% csrf_token %}
{{ form.as_p}}
<input class="mt-3" type="submit" value="Submit" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
</div>
</div>
</div>
{% endblock %}

password_reset_complete.html

{% extends "base.html" %}{% block content %}
<div class="container">
<div class="row justify-content-center align-items-center" style="height:80vh;">
<div class="col-auto border p-3">
You have successfully reset your password!.
</div>
</div>
</div>
{% endblock %}

For sign_up we need to make custom view. Create custom MySignUpView in views.py:

from django.shortcuts import render, redirect
from django.http import HttpResponseRedirect
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
from django.views import View
class MySignUpView(View):
form_class = UserCreationForm
template_name = 'registration/sign_up.html'
def get(self, request, *args, **kwargs):
form = self.form_class()
return render(request, self.template_name, {'form': form})
def post(self, request, *args, **kwargs):
form = self.form_class(request.POST)
if form.is_valid():
# <process form cleaned data>
u = User.objects.create_user(
form.cleaned_data.get('username'),
'',# request.POST['email'],
form.cleaned_data.get('password1'),
is_active = True
)
# TODO Display message and redirect to login
return HttpResponseRedirect('/accounts/login/?next=/')
return render(request, self.template_name, {'form': form})

Create corresponding sign_up.html

{% extends "base.html" %}{% block content %}
<div class="container">
<div class="row justify-content-center align-items-center" style="height:80vh;">
<div class="col-auto border p-3">
{% if form.errors %}
<p class="bg-danger p-2">Please give correct information !</p>
{% endif %}
<form method="post" action="">
{% csrf_token %}
{{ form.as_p}}
<input class="mt-3" type="submit" value="Submit" />
<input type="hidden" name="next" value="{{ next }}" />
</form>
</div>
</div>
</div>
{% endblock %}

Now we need to make changes in navbar to link login, logout, sign_up and change_password.

Edit templates/header.html

...
<a id="home" class="nav-item nav-link active" href="/#home">HOME</a>
{% if not user.is_authenticated %} <!-- if not logged in --><a class="nav-item nav-link" href="{% url 'accounts:login' %}?next=/">LOGIN</a><a class="nav-item nav-link" href="{% url 'accounts:sign_up' %}">SIGN_UP</a>
{% else %}
<a class="nav-item nav-link" href="{% url 'accounts:password_change' %}">CHANGE_PASSWORD</a><a class="nav-item nav-link" href="{% url 'accounts:logout' %}">LOGOUT</a>
{% endif %}
</div>
...

Thats it everything is ready now. Now test your development server using

$ ./manage.py runserver

And everything is set now:

Login page
sign up page

Everything seems working fine ! isn’t it ?

wait, but what about password_reset ?

To reset the password we requires 2 settings:

  1. Valid email in user.
  2. Valid email settings in main/settings.py
  3. How to set email for user when there is no email field in sign_up page ?

Ans: For testing purpose you can simply login with superuser account in localhost:8000/admin page. and update the email field.

Other solution is to extend UserCreationForm in registration/forms.py and then make small change in MySignUpView in views.py

2. But are the required email settings to send mail from django ?

Ans: Just append following settings in setting.py

# Email configurations
EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST='smtp.xyz.com' # Set your email host
EMAIL_PORT=587
EMAIL_HOST_USER='abc@xyz.com'
EMAIL_HOST_PASSWORD='******' #Your password
EMAIL_USE_TLS=True
DEFAULT_FROM_EMAIL = 'abc@xyz.com'

Thats it.

Your final project will look like this:

Thanks for reading and trying this out. If you have any doubts you can contact me directly here.

I have tried to cover small gaps that remains there even after following official docs and studying various answer on stack overflow like platforms. I hope you directly use it in your projects.

--

--