Django supports multiple authentication backends, allowing you to authenticate against various sources.
pip install django
django-admin startproject myproject
cd myproject
python manage.py startapp myapp
Add django.contrib.auth and your app (myapp) to INSTALLED_APPS.
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'myapp',
]
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect
def signup(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect('login')
else:
form = UserCreationForm()
return render(request, 'signup.html', {'form': form})
def user_login(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
return render(request, 'login.html', {'error': 'Invalid credentials'})
return render(request, 'login.html')
def user_logout(request):
logout(request)
return redirect('login')
from django.contrib.auth import authenticate, login, logout
from django.contrib.auth.forms import UserCreationForm
from django.shortcuts import render, redirect
def signup(request):
if request.method == 'POST':
form = UserCreationForm(request.POST)
if form.is_valid():
form.save()
return redirect('login')
else:
form = UserCreationForm()
return render(request, 'signup.html', {'form': form})
def user_login(request):
if request.method == 'POST':
username = request.POST['username']
password = request.POST['password']
user = authenticate(request, username=username, password=password)
if user is not None:
login(request, user)
return redirect('home')
else:
return render(request, 'login.html', {'error': 'Invalid credentials'})
return render(request, 'login.html')
def user_logout(request):
logout(request)
return redirect('login')
from django.contrib import admin
from django.urls import path
from myapp import views
urlpatterns = [
path('admin/', admin.site.urls),
path('signup/', views.signup, name='signup'),
path('login/', views.user_login, name='login'),
path('logout/', views.user_logout, name='logout'),
path('', views.home, name='home'), # Define a home view in views.py
]
Create HTML templates for signup.html, login.html, and other views in a templates directory inside your app.
<!DOCTYPE html>
<html>
<head>
<title>Sign Up</title>
</head>
<body>
<h2>Sign Up</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign Up</button>
</form>
</body>
</html>
login.html
<!DOCTYPE html>
<html>
<head>
<title>Login</title>
</head>
<body>
<h2>Login</h2>
{% if error %}
<p style="color: red;">{{ error }}</p>
{% endif %}
<form method="post">
{% csrf_token %}
<label for="username">Username:</label>
<input type="text" id="username" name="username">
<label for="password">Password:</label>
<input type="password" id="password" name="password">
<button type="submit">Login</button>
</form>
</body>
</html>
Django provides built-in views for login, logout, and password management which you can use directly. For instance:
from django.urls import path
from django.contrib.auth import views as auth_views
urlpatterns = [
path('admin/', admin.site.urls),
path('signup/', views.signup, name='signup'),
path('login/', auth_views.LoginView.as_view(template_name='login.html'), name='login'),
path('logout/', auth_views.LogoutView.as_view(), name='logout'),
path('password_change/', auth_views.PasswordChangeView.as_view(), name='password_change'),
path('password_change/done/', auth_views.PasswordChangeDoneView.as_view(), name='password_change_done'),
path('password_reset/', auth_views.PasswordResetView.as_view(), name='password_reset'),
path('password_reset/done/', auth_views.PasswordResetDoneView.as_view(), name='password_reset_done'),
path('reset/<uidb64>/<token>/', auth_views.PasswordResetConfirmView.as_view(), name='password_reset_confirm'),
path('reset/done/', auth_views.PasswordResetCompleteView.as_view(), name='password_reset_complete'),
]
The login_required decorator is the most straightforward way to protect a view. You simply add it above your view function. If a user is not authenticated, they will be redirected to the login page.
from django.contrib.auth.decorators import login_required
from django.shortcuts import render
@login_required
def protected_view(request):
return render(request, 'protected.html')
in `settings.py`: Ensure that you have a login URL specified so that the decorator knows where to redirect unauthenticated users.
LOGIN_URL = '/login/'
For class-based views, you can use the LoginRequiredMixin provided by Django.
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import TemplateView
class ProtectedView(LoginRequiredMixin, TemplateView):
template_name = 'protected.html'
You can also protect an entire set of URLs by using django.contrib.auth.decorators.login_required in your URL configuration.
from django.urls import path
from django.contrib.auth.decorators import login_required
from myapp import views
urlpatterns = [
path('protected/', login_required(views.protected_view), name='protected'),
]
In Django, permissions and groups are a key part of the authentication framework. They allow you to define what actions users can perform and to manage user roles more efficiently. Here's a detailed explanation:
Permissions in Django are used to define what actions a user can perform. By default, Django provides three permissions for each model:
These permissions are created when you run makemigrations and migrate.
You can also define custom permissions in your models.
from django.db import models
class MyModel(models.Model):
name = models.CharField(max_length=100)
class Meta:
permissions = [
('can_publish', 'Can Publish Posts'),
]
You can check permissions in your views or templates.
from django.shortcuts import render
from django.contrib.auth.decorators import permission_required
@permission_required('mymodel.can_publish')
def my_view(request):
return render(request, 'my_template.html')
Groups in Django allow you to categorize users and assign permissions to these groups, which can then be inherited by the users in the group. This is useful for managing roles within an application.
You can create and assign groups either through the Django admin interface or programmatically.
`management/commands/assign_groups.py`
from django.core.management.base import BaseCommand
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType
from myapp.models import MyModel
class Command(BaseCommand):
def handle(self, *args, **options):
# Create a group
group, created = Group.objects.get_or_create(name='Editors')
# Add permissions to group
content_type = ContentType.objects.get_for_model(MyModel)
permissions = Permission.objects.filter(content_type=content_type)
for permission in permissions:
group.permissions.add(permission)
# Assign group to a user
from django.contrib.auth.models import User
user = User.objects.get(username='john')
user.groups.add(group)
user.save()
You can use decorators or mixins to enforce permissions in your views.
from django.shortcuts import render
from django.contrib.auth.decorators import permission_required
from django.contrib.auth.decorators import login_required
@login_required
@permission_required('mymodel.can_publish', raise_exception=True)
def my_view(request):
return render(request, 'my_template.html')
For class-based views, use the `PermissionRequiredMixin`.
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic import TemplateView
class MyView(PermissionRequiredMixin, TemplateView):
template_name = 'my_template.html'
permission_required = 'mymodel.can_publish'
You can also check for permissions and group memberships in your templates.
{% if user.has_perm('mymodel.can_publish') %}
You have permission to publish posts.
{% else %}
You do not have permission to publish posts.
{% endif %}
{% if user.groups.filter(name='Editors').exists %}
You are an editor.
{% else %}
You are not an editor.
{% endif %}
Basic authentication uses the HTTPBasicAuthentication class, where the client sends the username and password encoded in the HTTP headers.
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
Token authentication uses the TokenAuthentication class. Each user is assigned a unique token, which they must include in the Authorization header of their requests.
pip install djangorestframework drf-yasg
pip install djangorestframework-authtoken
Add rest_framework and rest_framework.authtoken to your INSTALLED_APPS
INSTALLED_APPS = [
...
'rest_framework',
'rest_framework.authtoken',
...
]
python manage.py migrate
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
class CustomAuthToken(ObtainAuthToken):
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data,
context={'request': request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({
'token': token.key,
'user_id': user.pk,
'email': user.email
})
from django.urls import path
from myapp.views import CustomAuthToken
urlpatterns = [
path('api-token-auth/', CustomAuthToken.as_view()),
]
Session authentication uses Django's session framework. It’s suitable for web applications where the client and server share the same session
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.SessionAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
JWT (JSON Web Token) authentication is commonly used for API authentication. It provides a compact and self-contained way to securely transmit information between parties as a JSON object.
pip install djangorestframework-simplejwt
from datetime import timedelta
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=5),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'ROTATE_REFRESH_TOKENS': False,
'BLACKLIST_AFTER_ROTATION': True,
'ALGORITHM': 'HS256',
'SIGNING_KEY': SECRET_KEY,
'VERIFYING_KEY': None,
'AUTH_HEADER_TYPES': ('Bearer',),
}
Update urls.py
from django.urls import path
from rest_framework_simplejwt.views import (
TokenObtainPairView,
TokenRefreshView,
)
urlpatterns = [
path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]
You can create custom authentication classes by extending the BaseAuthentication class. in authentication.py
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from django.contrib.auth.models import User
class CustomAuthentication(BaseAuthentication):
def authenticate(self, request):
token = request.META.get('HTTP_AUTHORIZATION')
if not token:
return None
try:
user = User.objects.get(auth_token=token)
except User.DoesNotExist:
raise AuthenticationFailed('Invalid token')
return (user, None)
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'myapp.authentication.CustomAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
}
You can use the IsAuthenticated permission class to ensure that only authenticated users can access certain views. You can also create custom permission classes.
Example of Using Built-in Permissions in `views.py`
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):
content = {'message': 'This is a protected view'}
return Response(content)
Example of a Custom Permission Class in `permissions.py`
from rest_framework.permissions import BasePermission
class IsAdminUser(BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_staff
views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from myapp.permissions import IsAdminUser
class AdminView(APIView):
permission_classes = [IsAdminUser]
def get(self, request):
content = {'message': 'This is an admin view'}
return Response(content)
By configuring these authentication methods, you can secure your Django REST Framework API and ensure that only authorized users can access or modify resources.