Introduction to Django Authentication
Authentication is the cornerstone of most web applications, enabling personalized experiences while protecting sensitive information. Django's authentication system is robust, secure, and flexible – allowing developers to focus on building application features rather than reinventing security fundamentals.
Think of Django's authentication as a complete security checkpoint system for your web application – it verifies identities, manages access permissions, and maintains secure sessions, all while providing convenient shortcuts for these common tasks.
Key components of Django's authentication system:
- Users and Groups: Django provides ready-to-use models for managing users and organizing them into groups
- Permissions: A granular system for defining what actions users can perform
- Authentication: Secure password handling and identity verification
- Authorization: Mechanisms to control access to views and resources
- Sessions: Secure, cookie-based user sessions
The Django User Model
At the core of Django's authentication system is the User model, which stores user credentials and basic information.
By default, Django's built-in User model includes:
- username: Required. 150 characters or fewer, unique
- password: Required. Stored using secure hashing
- email: Optional. Email address
- first_name: Optional. 150 characters or fewer
- last_name: Optional. 150 characters or fewer
- is_active: Boolean. Designates if account is active
- is_staff: Boolean. Determines admin site access
- is_superuser: Boolean. Designates all permissions without assignment
- date_joined: Datetime. Account creation time
- last_login: Datetime. Last login time
Using the User Model
from django.contrib.auth.models import User
# Creating a user
user = User.objects.create_user(
username='johndoe',
email='john@example.com',
password='securepassword123'
)
# Note: Always use create_user() method, not User.objects.create()
# This ensures the password is properly hashed
# Updating user details
user.first_name = 'John'
user.last_name = 'Doe'
user.save()
# Checking credentials (in a view)
from django.contrib.auth import authenticate
user = authenticate(username='johndoe', password='securepassword123')
if user is not None:
# Authentication successful
pass
else:
# Authentication failed
pass
Custom User Model
Django recommends using a custom user model for new projects, even if it's initially identical to the default User model. This provides flexibility for future changes.
Real-world analogy: Think of this like buying a slightly larger suit than you need right now. You might not need the extra room today, but it's much easier to make alterations later than to replace the entire suit.
# models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
# Add custom fields here
bio = models.TextField(blank=True)
birth_date = models.DateField(null=True, blank=True)
profile_picture = models.ImageField(upload_to='profile_pics/', null=True, blank=True)
# You can also override existing fields if needed
In your settings.py, specify the custom model:
# settings.py
AUTH_USER_MODEL = 'myapp.User'
Important! Setting AUTH_USER_MODEL must be done before creating any migrations. Changing it after your database is established is extremely difficult.
Email-Based Authentication
Many modern applications use email instead of username for authentication. Here's how to implement that:
# models.py
from django.contrib.auth.models import AbstractUser, BaseUserManager
from django.db import models
class UserManager(BaseUserManager):
def create_user(self, email, password=None, **extra_fields):
if not email:
raise ValueError('Users must have an email address')
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)
extra_fields.setdefault('is_active', True)
return self.create_user(email, password, **extra_fields)
class User(AbstractUser):
username = None # Remove username field
email = models.EmailField('email address', unique=True)
# Add custom fields
bio = models.TextField(blank=True)
USERNAME_FIELD = 'email' # Use email as the unique identifier
REQUIRED_FIELDS = [] # Email & password are required by default
objects = UserManager()
User Authentication
Django provides complete functionality for authenticating users securely. The key components include:
Implementing Login Views
Django offers pre-built views for authentication, but knowing how to implement them manually is valuable:
# views.py
from django.contrib.auth import authenticate, login
from django.contrib.auth.forms import AuthenticationForm
from django.shortcuts import render, redirect
def login_view(request):
if request.method == 'POST':
form = AuthenticationForm(request, data=request.POST)
if form.is_valid():
username = form.cleaned_data.get('username')
password = form.cleaned_data.get('password')
user = authenticate(username=username, password=password)
if user is not None:
login(request, user)
# Redirect to a success page
return redirect('home')
else:
form = AuthenticationForm()
return render(request, 'login.html', {'form': form})
And in your template:
<!-- login.html -->
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Log In</button>
</form>
Using Django's Authentication Views
Django provides ready-made views for authentication tasks. These handle the logic, but you need to create matching templates:
# urls.py
from django.contrib.auth import views as auth_views
from django.urls import path
urlpatterns = [
path('login/', auth_views.LoginView.as_view(template_name='login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(next_page='login'), name='logout'),
path('password-change/', auth_views.PasswordChangeView.as_view(template_name='password_change.html'), name='password_change'),
path('password-change/done/', auth_views.PasswordChangeDoneView.as_view(template_name='password_change_done.html'), name='password_change_done'),
# Password reset (forgot password) flow
path('password-reset/', auth_views.PasswordResetView.as_view(template_name='password_reset.html'), name='password_reset'),
path('password-reset/done/', auth_views.PasswordResetDoneView.as_view(template_name='password_reset_done.html'), name='password_reset_done'),
path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(template_name='password_reset_confirm.html'), name='password_reset_confirm'),
path('reset/done/', auth_views.PasswordResetCompleteView.as_view(template_name='password_reset_complete.html'), name='password_reset_complete'),
]
For these built-in views to work, you need to create templates with matching names.
Implementing User Registration
Django doesn't include built-in registration views, but you can easily create them:
# forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from django.contrib.auth import get_user_model
User = get_user_model()
class CustomUserCreationForm(UserCreationForm):
email = forms.EmailField(required=True)
class Meta:
model = User
fields = ('username', 'email', 'password1', 'password2')
def save(self, commit=True):
user = super().save(commit=False)
user.email = self.cleaned_data['email']
if commit:
user.save()
return user
# views.py
from django.shortcuts import render, redirect
from .forms import CustomUserCreationForm
from django.contrib.auth import login
def register_view(request):
if request.method == 'POST':
form = CustomUserCreationForm(request.POST)
if form.is_valid():
user = form.save()
login(request, user) # Log in the user immediately after registration
return redirect('home')
else:
form = CustomUserCreationForm()
return render(request, 'register.html', {'form': form})
Security Note: Always use Django's built-in password handling functions like set_password() and never store passwords in plain text. Django takes care of secure hashing and salting automatically.
Managing Sessions
Django's session framework handles user sessions securely. When a user logs in, Django creates a session and stores a session cookie in the user's browser.
Session Configuration
Django offers several session storage options, configured in settings.py:
# settings.py
# Default: database-backed sessions
SESSION_ENGINE = 'django.contrib.sessions.backends.db'
# Other options:
# SESSION_ENGINE = 'django.contrib.sessions.backends.file' # File-based sessions
# SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # Cache-based sessions
# SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # Cache & DB hybrid
# SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # Cookie-based
# Session cookie settings
SESSION_COOKIE_AGE = 1209600 # 2 weeks, in seconds
SESSION_COOKIE_SECURE = True # Only send over HTTPS
SESSION_COOKIE_HTTPONLY = True # Prevent JavaScript access
Working with Sessions
Django makes it easy to work with session data:
# Store data in the session
request.session['key'] = 'value'
# Get data from the session
value = request.session.get('key', 'default') # Default if key doesn't exist
# Delete data from the session
del request.session['key']
# Check if a key exists
if 'key' in request.session:
# Do something
# Clear all session data
request.session.flush()
Real-world example: You might use sessions to store a user's shopping cart even if they're not logged in, or to remember their site preferences for a personalized experience.
# views.py
def add_to_cart(request, product_id):
# Initialize cart if it doesn't exist
if 'cart' not in request.session:
request.session['cart'] = {}
# Add or increment product in cart
cart = request.session['cart']
if product_id in cart:
cart[product_id] += 1
else:
cart[product_id] = 1
# Important: mark the session as modified
request.session.modified = True
return redirect('cart')
Important! When modifying nested session data (like dictionaries or lists), you must explicitly set request.session.modified = True for Django to save the changes.
User Authorization
Authorization determines what authenticated users are allowed to do. Django provides a comprehensive system for defining and checking permissions.
The Permission System
Django automatically creates four permissions for each model:
add_modelname: Can add a model instancechange_modelname: Can modify a model instancedelete_modelname: Can delete a model instanceview_modelname: Can view a model instance
Custom Permissions
You can define custom permissions on your models:
# models.py
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(User, on_delete=models.CASCADE)
published = models.BooleanField(default=False)
class Meta:
permissions = [
("publish_article", "Can publish articles"),
("feature_article", "Can feature articles on homepage"),
]
Checking Permissions
Django provides several ways to check permissions:
# In Python code
# Check if a user has a specific permission
if user.has_perm('myapp.publish_article'):
# Allow publishing
pass
# Multiple permission check
if user.has_perms(['myapp.publish_article', 'myapp.feature_article']):
# Allow both actions
pass
# In templates
{% if perms.myapp.publish_article %}
<button>Publish</button>
{% endif %}
Decorators for View Protection
Django provides decorators to restrict access to views:
from django.contrib.auth.decorators import login_required, permission_required
# Require login
@login_required
def profile_view(request):
# Only authenticated users can access
return render(request, 'profile.html')
# Require specific permission
@permission_required('myapp.publish_article')
def publish_article(request, article_id):
# Only users with publish permission can access
article = get_object_or_404(Article, id=article_id)
article.published = True
article.save()
return redirect('article_detail', article_id=article_id)
# Multiple permissions (AND logic)
@permission_required(['myapp.publish_article', 'myapp.feature_article'])
def publish_and_feature(request, article_id):
# User needs both permissions
pass
# With custom redirect and message
@login_required(login_url='/accounts/login/', redirect_field_name='next')
def dashboard(request):
# If not logged in, redirects to /accounts/login/?next=original_url
pass
Mixins for Class-Based Views
For class-based views, Django provides mixins for authorization:
from django.contrib.auth.mixins import LoginRequiredMixin, PermissionRequiredMixin
from django.views.generic import ListView, DetailView, UpdateView
# Require login
class ProfileView(LoginRequiredMixin, DetailView):
model = User
template_name = 'profile.html'
# Customize redirect
login_url = '/login/'
redirect_field_name = 'next'
# Require permission
class ArticleUpdateView(LoginRequiredMixin, PermissionRequiredMixin, UpdateView):
model = Article
template_name = 'article_edit.html'
fields = ['title', 'content']
# Permission settings
permission_required = 'myapp.change_article'
# OR logic for multiple permissions (default is AND)
permission_required = ['myapp.change_article', 'myapp.publish_article']
raise_exception = True # Raise 403 instead of redirecting to login
Groups and Role-Based Access
For most applications, it's more manageable to assign permissions to groups rather than individual users. This implements "role-based access control" (RBAC).
Working with Groups
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from myapp.models import Article
# Create a new group
editors_group, created = Group.objects.get_or_create(name='Editors')
# Get content type for the model
content_type = ContentType.objects.get_for_model(Article)
# Get permissions
publish_permission = Permission.objects.get(
codename='publish_article',
content_type=content_type,
)
change_permission = Permission.objects.get(
codename='change_article',
content_type=content_type,
)
# Add permissions to group
editors_group.permissions.add(publish_permission, change_permission)
# Add user to group
user = User.objects.get(username='johndoe')
user.groups.add(editors_group)
# Check if user is in group
if user.groups.filter(name='Editors').exists():
# User is an editor
pass
Admin Integration
Groups and permissions can be managed through Django's admin interface:
# admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.models import User, Group
# Already registered by django.contrib.auth
# admin.site.register(User, UserAdmin)
# admin.site.register(Group)
# If you have a custom user model
from .models import CustomUser
class CustomUserAdmin(UserAdmin):
# Add your customizations
list_display = UserAdmin.list_display + ('custom_field',)
admin.site.register(CustomUser, CustomUserAdmin)
Real-world example: A news website might have groups like "Writers" (can create and edit their own articles), "Editors" (can edit and publish any article), and "Admins" (can manage users and site settings).
Object-Level Permissions
Sometimes you need finer permission control beyond model-level permissions. For example, a user might be allowed to edit only their own articles, not anyone else's.
Custom Permission Checks
# views.py
@login_required
def edit_article(request, article_id):
article = get_object_or_404(Article, id=article_id)
# Check if user is the author
if request.user != article.author:
# Use Django's permission denied shortcut
from django.core.exceptions import PermissionDenied
raise PermissionDenied
# Process edit
# ...
Using get_queryset in Class-Based Views
from django.views.generic import UpdateView
class ArticleUpdateView(LoginRequiredMixin, UpdateView):
model = Article
fields = ['title', 'content']
template_name = 'article_edit.html'
def get_queryset(self):
# Filter queryset to only include user's own articles
return Article.objects.filter(author=self.request.user)
Django Guardian for Object Permissions
For complex object-level permissions, consider using the django-guardian package:
# Install with pip
# pip install django-guardian
# Add to INSTALLED_APPS
# settings.py
INSTALLED_APPS = [
# ...
'guardian',
]
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend', # Default
'guardian.backends.ObjectPermissionBackend',
]
Using django-guardian:
from guardian.shortcuts import assign_perm, remove_perm, get_objects_for_user
# Assign object permission
article = Article.objects.get(pk=1)
user = User.objects.get(username='johndoe')
assign_perm('change_article', user, article)
# Check object permission
if user.has_perm('change_article', article):
# User can edit this specific article
pass
# Get objects user has permission for
editable_articles = get_objects_for_user(
user,
'myapp.change_article',
klass=Article
)
Authentication in Templates
Django makes it easy to access user authentication information in templates:
<!-- Base template with authentication UI -->
<div class="navigation">
{% if user.is_authenticated %}
<span>Hello, {{ user.username }}!</span>
<a href="{% url 'profile' %}">My Profile</a>
<a href="{% url 'logout' %}">Logout</a>
{% if user.is_staff %}
<a href="{% url 'admin:index' %}">Admin</a>
{% endif %}
{% else %}
<a href="{% url 'login' %}">Login</a>
<a href="{% url 'register' %}">Register</a>
{% endif %}
</div>
<!-- Permission-based UI elements -->
{% if perms.myapp.add_article %}
<a href="{% url 'article_create' %}" class="button">Write New Article</a>
{% endif %}
{% if perms.myapp.publish_article %}
<div class="admin-tools">
<h3>Publishing Tools</h3>
<!-- Publishing interface elements -->
</div>
{% endif %}
Note: The user variable is automatically available in templates when using RequestContext, which is the default in Django's render function.
Authentication Backends
Django's authentication system is extensible through custom backends, allowing authentication against different sources like LDAP, OAuth, or custom systems.
Using Multiple Authentication Backends
# settings.py
AUTHENTICATION_BACKENDS = [
'django.contrib.auth.backends.ModelBackend', # Default database backend
'myapp.auth_backends.EmailBackend', # Custom email backend
'myapp.auth_backends.LDAPBackend', # Custom LDAP backend
]
Django tries each backend in order until one successfully authenticates the user.
Creating a Custom Backend
Here's an example of a simple email authentication backend:
# myapp/auth_backends.py
from django.contrib.auth import get_user_model
from django.contrib.auth.backends import ModelBackend
User = get_user_model()
class EmailBackend(ModelBackend):
def authenticate(self, request, username=None, password=None, **kwargs):
# Check if username is actually an email address
if '@' in username:
try:
user = User.objects.get(email=username)
if user.check_password(password):
return user
except User.DoesNotExist:
return None
return None
This allows users to log in with either username or email using the same login form.
Security Best Practices
Authentication is a critical security aspect. Here are some best practices:
Password Management
- Password Hashing: Django uses PBKDF2 with SHA256 by default, which is secure
- Password Validation: Enforce strong passwords
- Throttling Attempts: Limit login attempts to prevent brute force attacks
# settings.py
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
'OPTIONS': {
'min_length': 10,
}
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
Implementing Login Throttling
Django doesn't include login throttling by default, but you can add it with django-axes:
# pip install django-axes
# settings.py
INSTALLED_APPS = [
# ...
'axes',
]
MIDDLEWARE = [
# ...
# Should be the last middleware
'axes.middleware.AxesMiddleware',
]
AUTHENTICATION_BACKENDS = [
# AxesBackend should be the first backend
'axes.backends.AxesBackend',
'django.contrib.auth.backends.ModelBackend',
]
# Axes settings
AXES_FAILURE_LIMIT = 5 # Number of login attempts allowed
AXES_COOLOFF_TIME = 1 # Lockout time in hours
HTTPS and Secure Cookies
# settings.py
# Always use HTTPS in production
SECURE_SSL_REDIRECT = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
# Secure cookies
SESSION_COOKIE_SECURE = True
CSRF_COOKIE_SECURE = True
SESSION_COOKIE_HTTPONLY = True
CSRF_COOKIE_HTTPONLY = True
# HSTS settings
SECURE_HSTS_SECONDS = 31536000 # 1 year
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
SECURE_HSTS_PRELOAD = True
Two-Factor Authentication
For enhanced security, consider implementing two-factor authentication using packages like django-two-factor-auth.
Real-World Authentication System Example
Let's build a complete authentication system for a blog application, incorporating best practices.
Project Structure
blog/
├── blog/
│ ├── __init__.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
├── articles/
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── models.py
│ ├── views.py
│ └── urls.py
└── users/
├── __init__.py
├── admin.py
├── apps.py
├── forms.py
├── models.py
├── views.py
├── urls.py
└── templates/
└── users/
├── login.html
├── register.html
├── profile.html
└── password_reset.html
Custom User Model
# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class User(AbstractUser):
bio = models.TextField(blank=True)
profile_picture = models.ImageField(upload_to='profile_pics/', null=True, blank=True)
# User roles
is_author = models.BooleanField(default=False)
is_editor = models.BooleanField(default=False)
Registration Form
# users/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm
from .models import User
class UserRegisterForm(UserCreationForm):
email = forms.EmailField()
class Meta:
model = User
fields = ['username', 'email', 'password1', 'password2']
class UserUpdateForm(forms.ModelForm):
class Meta:
model = User
fields = ['username', 'email', 'bio', 'profile_picture']
Authentication Views
# users/views.py
from django.shortcuts import render, redirect
from django.contrib import messages
from django.contrib.auth.decorators import login_required
from .forms import UserRegisterForm, UserUpdateForm
def register(request):
if request.method == 'POST':
form = UserRegisterForm(request.POST)
if form.is_valid():
user = form.save()
messages.success(request, f'Account created! You can now log in.')
return redirect('login')
else:
form = UserRegisterForm()
return render(request, 'users/register.html', {'form': form})
@login_required
def profile(request):
if request.method == 'POST':
form = UserUpdateForm(request.POST, request.FILES, instance=request.user)
if form.is_valid():
form.save()
messages.success(request, f'Your profile has been updated!')
return redirect('profile')
else:
form = UserUpdateForm(instance=request.user)
return render(request, 'users/profile.html', {'form': form})
URL Configuration
# users/urls.py
from django.urls import path
from django.contrib.auth import views as auth_views
from . import views
urlpatterns = [
path('register/', views.register, name='register'),
path('profile/', views.profile, name='profile'),
path('login/', auth_views.LoginView.as_view(template_name='users/login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(template_name='users/logout.html'), name='logout'),
path('password-reset/',
auth_views.PasswordResetView.as_view(template_name='users/password_reset.html'),
name='password_reset'),
path('password-reset/done/',
auth_views.PasswordResetDoneView.as_view(template_name='users/password_reset_done.html'),
name='password_reset_done'),
path('password-reset-confirm/<uidb64>/<token>/',
auth_views.PasswordResetConfirmView.as_view(template_name='users/password_reset_confirm.html'),
name='password_reset_confirm'),
path('password-reset-complete/',
auth_views.PasswordResetCompleteView.as_view(template_name='users/password_reset_complete.html'),
name='password_reset_complete'),
]
Main URL Configuration
# blog/urls.py
from django.contrib import admin
from django.urls import path, include
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('articles.urls')),
path('users/', include('users.urls')),
]
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
Settings Configuration
# blog/settings.py
AUTH_USER_MODEL = 'users.User'
LOGIN_REDIRECT_URL = 'home'
LOGIN_URL = 'login'
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_PASS')
Social Authentication
Many applications provide social login options (Google, Facebook, GitHub, etc.). Django can integrate these using django-allauth:
# pip install django-allauth
# settings.py
INSTALLED_APPS = [
# ...
'django.contrib.sites',
'allauth',
'allauth.account',
'allauth.socialaccount',
'allauth.socialaccount.providers.google',
'allauth.socialaccount.providers.github',
]
MIDDLEWARE = [
# ...
'allauth.account.middleware.AccountMiddleware',
]
AUTHENTICATION_BACKENDS = [
# ...
'allauth.account.auth_backends.AuthenticationBackend',
]
SITE_ID = 1
# Allauth settings
ACCOUNT_EMAIL_REQUIRED = True
ACCOUNT_EMAIL_VERIFICATION = 'mandatory'
ACCOUNT_UNIQUE_EMAIL = True
ACCOUNT_USERNAME_REQUIRED = False
ACCOUNT_AUTHENTICATION_METHOD = 'email'
ACCOUNT_LOGOUT_ON_GET = True
# Provider specific settings
SOCIALACCOUNT_PROVIDERS = {
'google': {
'APP': {
'client_id': 'your-client-id',
'secret': 'your-secret-key',
'key': ''
}
}
}
Add to URLs:
# urls.py
urlpatterns = [
# ...
path('accounts/', include('allauth.urls')),
]
JWT Authentication for APIs
For RESTful APIs, JSON Web Tokens (JWT) are often used for authentication. Django REST framework and django-rest-framework-simplejwt can handle this:
# pip install djangorestframework django-rest-framework-simplejwt
# settings.py
INSTALLED_APPS = [
# ...
'rest_framework',
]
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework_simplejwt.authentication.JWTAuthentication',
),
}
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=15),
'REFRESH_TOKEN_LIFETIME': timedelta(days=14),
'ROTATE_REFRESH_TOKENS': True,
'BLACKLIST_AFTER_ROTATION': True,
}
URLs for JWT endpoints:
# urls.py
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
TokenVerifyView,
)
urlpatterns = [
# ...
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
path('api/token/verify/', TokenVerifyView.as_view(), name='token_verify'),
]
Using JWT authentication in a view:
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated
class ProtectedView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request):
return Response({'message': f'Hello, {request.user.username}!'})
Practice Activities
Basic Exercise: User Registration System
Create a simple Django application with user registration, login, and profile pages. Add basic profile fields and implement password change functionality.
Intermediate Exercise: Role-Based Permissions
Extend the basic exercise by adding user roles (e.g., Admin, Editor, Viewer) with appropriate permissions. Create views that are only accessible to specific roles.
Advanced Exercise: OAuth Integration
Implement social authentication with at least two providers (e.g., Google and GitHub) using django-allauth. Create a unified profile system that works for both traditional and social accounts.
Challenge: Custom Authentication Backend
Create a custom authentication backend that allows users to log in with either username, email, or phone number. Add appropriate validation and security measures.