Django Login System
Introduction
A login system is a fundamental component of most web applications that require user accounts. Django provides a robust authentication framework that makes it easy to implement secure login functionality without having to build everything from scratch.
In this tutorial, we'll explore how to create a complete login system in Django. We'll cover user authentication, creating login forms, managing sessions, and implementing common login-related features like password reset and "remember me" functionality.
Prerequisites
Before we begin, you should have:
- Basic understanding of Django
- Python and Django installed on your system
- A Django project set up
Django's Authentication Framework
Django's built-in authentication system handles user accounts, groups, permissions, and cookie-based user sessions. It includes:
- User objects with essential fields like username, password, email, etc.
- Authentication functions to verify usernames and passwords
- Views for common actions like login, logout, and password change
Setting Up Authentication
Django's authentication system is included by default when you create a new project. Make sure these apps are in your INSTALLED_APPS
in settings.py
:
INSTALLED_APPS = [
# ...
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
# ...
]
Also, ensure these middlewares are included:
MIDDLEWARE = [
# ...
'django.contrib.sessions.middleware.SessionMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
# ...
]
Creating Login Views
Django provides built-in views for handling user authentication. Let's set up the basic login functionality.
Step 1: Configure URLs
First, let's include the authentication URLs in your project's urls.py
file:
from django.urls import path, include
from django.contrib.auth import views as auth_views
urlpatterns = [
# Your other URL patterns
path('accounts/', include('django.contrib.auth.urls')),
]
This includes several authentication-related URLs:
accounts/login/
- Login pageaccounts/logout/
- Logout pageaccounts/password_change/
- Password change formaccounts/password_change/done/
- Password change successaccounts/password_reset/
- Password reset formaccounts/password_reset/done/
- Password reset doneaccounts/reset/<uidb64>/<token>/
- Password reset confirmationaccounts/reset/done/
- Password reset complete
Step 2: Create Login Templates
Django's authentication views look for templates in specific locations. Let's create a login template at templates/registration/login.html
:
{% extends 'base.html' %}
{% block content %}
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
<p>Don't have an account? <a href="{% url 'register' %}">Register here</a></p>
<p><a href="{% url 'password_reset' %}">Forgot password?</a></p>
{% endblock %}
Step 3: Configure Login Settings
Add these settings to your settings.py
:
# URLs to redirect to after login/logout
LOGIN_REDIRECT_URL = 'home' # Replace 'home' with your desired redirect page
LOGOUT_REDIRECT_URL = 'home'
# Login URL (used by login_required decorator)
LOGIN_URL = 'login'
Creating a Custom Login View
If you need more control, you can create your own login view:
# views.py
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login
from django.contrib import messages
from .forms import LoginForm
def login_view(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Get the 'next' parameter value for redirection after login
next_url = request.GET.get('next', 'home')
return redirect(next_url)
else:
messages.error(request, "Invalid username or password.")
else:
form = LoginForm()
return render(request, 'accounts/login.html', {'form': form})
And the corresponding form:
# forms.py
from django import forms
class LoginForm(forms.Form):
username = forms.CharField(max_length=150)
password = forms.CharField(widget=forms.PasswordInput)
remember_me = forms.BooleanField(required=False)
Then add the view to your urls.py
:
from django.urls import path
from . import views
urlpatterns = [
path('login/', views.login_view, name='login'),
# Other URL patterns
]
Protecting Views with Login Required
To restrict access to certain views to logged-in users only, use the @login_required
decorator:
from django.contrib.auth.decorators import login_required
@login_required
def profile_view(request):
return render(request, 'accounts/profile.html')
For class-based views, use LoginRequiredMixin
:
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
class ProfileView(LoginRequiredMixin, TemplateView):
template_name = 'accounts/profile.html'
Implementing "Remember Me" Functionality
The "Remember Me" feature allows users to stay logged in even after closing their browser. Django handles this through session expiration settings:
# forms.py
class LoginForm(forms.Form):
username = forms.CharField(max_length=150)
password = forms.CharField(widget=forms.PasswordInput)
remember_me = forms.BooleanField(required=False)
# views.py
def login_view(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
remember_me = form.cleaned_data['remember_me']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
# Set session expiry based on remember_me checkbox
if not remember_me:
request.session.set_expiry(0) # Session expires when browser closes
# For remember_me=True, Django uses the default expiry (2 weeks by default)
return redirect('home')
else:
messages.error(request, "Invalid username or password.")
else:
form = LoginForm()
return render(request, 'accounts/login.html', {'form': form})
Adding User Registration
A complete login system typically includes user registration. Here's a simple implementation:
# forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class RegisterForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ["username", "email", "password1", "password2"]
# views.py
def register_view(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
messages.success(request, "Registration successful!")
return redirect('home')
else:
messages.error(request, "Registration failed. Please correct the errors.")
else:
form = RegisterForm()
return render(request, 'accounts/register.html', {'form': form})
<!-- templates/accounts/register.html -->
{% extends 'base.html' %}
{% block content %}
<h2>Register</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Register</button>
</form>
<p>Already have an account? <a href="{% url 'login' %}">Login here</a></p>
{% endblock %}
Complete Login System Example
Let's put everything together into a complete login system example:
Directory Structure
myproject/
│
├── myproject/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
│
├── accounts/
│ ├── __init__.py
│ ├── admin.py
│ ├── forms.py
│ ├── models.py
│ ├── tests.py
│ ├── urls.py
│ └── views.py
│
└── templates/
├── base.html
└── accounts/
├── login.html
├── register.html
└── profile.html
Implementation
# accounts/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth.models import User
class LoginForm(forms.Form):
username = forms.CharField(max_length=150)
password = forms.CharField(widget=forms.PasswordInput)
remember_me = forms.BooleanField(required=False)
class RegisterForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ["username", "email", "password1", "password2"]
# accounts/views.py
from django.shortcuts import render, redirect
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.decorators import login_required
from django.contrib import messages
from .forms import LoginForm, RegisterForm
def login_view(request):
if request.method == 'POST':
form = LoginForm(request.POST)
if form.is_valid():
username = form.cleaned_data['username']
password = form.cleaned_data['password']
remember_me = form.cleaned_data['remember_me']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
if not remember_me:
request.session.set_expiry(0)
messages.success(request, f"Welcome back, {username}!")
return redirect('profile')
else:
messages.error(request, "Invalid username or password.")
else:
form = LoginForm()
return render(request, 'accounts/login.html', {'form': form})
def logout_view(request):
logout(request)
messages.info(request, "You have been logged out.")
return redirect('login')
def register_view(request):
if request.method == 'POST':
form = RegisterForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user)
messages.success(request, "Registration successful!")
return redirect('profile')
else:
form = RegisterForm()
return render(request, 'accounts/register.html', {'form': form})
@login_required
def profile_view(request):
return render(request, 'accounts/profile.html')
# accounts/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('login/', views.login_view, name='login'),
path('logout/', views.logout_view, name='logout'),
path('register/', views.register_view, name='register'),
path('profile/', views.profile_view, name='profile'),
]
# myproject/urls.py
from django.contrib import admin
from django.urls import path, include
from django.views.generic import RedirectView
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('accounts.urls')),
path('', RedirectView.as_view(url='accounts/login/')),
]
Security Considerations
When implementing a login system, consider these security best practices:
-
Use HTTPS: Always use HTTPS in production to encrypt login credentials.
-
Password Hashing: Django automatically hashes passwords, but ensure you're using the latest hashing algorithms.
-
Password Policies: Consider implementing password strength requirements.
-
Brute Force Protection: Implement rate limiting to prevent brute force attacks.
-
CSRF Protection: Always include the
{% csrf_token %}
in your forms. -
Session Security: Configure secure cookie settings:
# settings.py
SESSION_COOKIE_SECURE = True # Cookies only sent over HTTPS
SESSION_COOKIE_HTTPONLY = True # Prevents JavaScript from accessing cookies
SESSION_COOKIE_SAMESITE = 'Lax' # Prevents CSRF attacks
Summary
In this tutorial, we've built a comprehensive Django login system that includes:
- User authentication with Django's built-in auth system
- Custom login and registration views
- "Remember Me" functionality
- Profile protection with login_required
- Security best practices
Django's authentication system provides a solid foundation for building secure user management features. By leveraging these built-in tools, you can focus on developing your application's unique features rather than reinventing secure authentication.
Additional Resources
Exercises
- Implement password reset functionality using Django's built-in views.
- Add a "change password" feature for logged-in users.
- Create a user profile model that extends Django's User model with additional information.
- Implement social authentication (GitHub, Google, etc.) using a package like django-allauth.
- Add two-factor authentication for enhanced security.
Happy coding!
If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)