Introduction
Welcome back to our Django REST Framework (DRF) adventure! In Part 1, we set up our Django project, installed DRF, and built the Task model. In Part 2, we implemented API endpoints for CRUD operations, allowing us to create, read, update, and delete tasks.
In Part 3, we’ll add authentication and permissions to our Task Manager API. This will ensure that only authenticated users can access and modify tasks. By the end of this guide, you’ll have a secure API where users can register, log in, and perform operations based on their permissions.
Let’s dive in!
Table of Contents
- Step 1: Set Up Django Authentication
- Step 2: Add DRF Token Authentication
- Step 3: Build Registration and Login Endpoints
- Step 4: Secure Your Task Endpoints
- Step 5: Test Your Secure API
- Conclusion
- What’s Next?
Step 1: Set Up Django Authentication
Django’s got a built-in authentication system that’s perfect for managing users. Let’s make sure it’s ready to roll.
In taskmanager/settings.py
, check that these apps are in INSTALLED_APPS
:
INSTALLED_APPS = [...'django.contrib.auth', # User management'django.contrib.contenttypes', # Required for auth'rest_framework', # DRF core'rest_framework.authtoken', # Token auth support'tasks', # Our app]INSTALLED_APPS = [ ... 'django.contrib.auth', # User management 'django.contrib.contenttypes', # Required for auth 'rest_framework', # DRF core 'rest_framework.authtoken', # Token auth support 'tasks', # Our app ]INSTALLED_APPS = [ ... 'django.contrib.auth', # User management 'django.contrib.contenttypes', # Required for auth 'rest_framework', # DRF core 'rest_framework.authtoken', # Token auth support 'tasks', # Our app ]
Enter fullscreen mode Exit fullscreen mode
Then, run migrations to apply the necessary database changes:
python manage.py migratepython manage.py migratepython manage.py migrate
Enter fullscreen mode Exit fullscreen mode
What’s this doing?
This sets up Django’s user tables (like auth_user) so we can handle logins and permissions. No extra work is needed—Django’s got your back!
Step 2: Add DRF Token Authentication
We’ll use Token Authentication from DRF, where each user gets a unique token to prove who they are. Update taskmanager/settings.py with:
REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': ('rest_framework.authentication.TokenAuthentication',),'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAuthenticated', # Only logged-in users allowed),}REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', # Only logged-in users allowed ), }REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': ( 'rest_framework.authentication.TokenAuthentication', ), 'DEFAULT_PERMISSION_CLASSES': ( 'rest_framework.permissions.IsAuthenticated', # Only logged-in users allowed ), }
Enter fullscreen mode Exit fullscreen mode
What’s happening?
-
TokenAuthentication
: Users send a token with requests to authenticate. -
IsAuthenticated
: Locks down all endpoints unless a valid token is provided.
To auto-generate tokens when users sign up, create tasks/signals.py:
from django.conf import settingsfrom django.db.models.signals import post_savefrom django.dispatch import receiverfrom rest_framework.authtoken.models import Tokenfrom django.contrib.auth.models import User@receiver(post_save, sender=User)def create_auth_token(sender, instance=None, created=False, **kwargs):if created:Token.objects.create(user=instance)from django.conf import settings from django.db.models.signals import post_save from django.dispatch import receiver from rest_framework.authtoken.models import Token from django.contrib.auth.models import User @receiver(post_save, sender=User) def create_auth_token(sender, instance=None, created=False, **kwargs): if created: Token.objects.create(user=instance)from django.conf import settings from django.db.models.signals import post_save from django.dispatch import receiver from rest_framework.authtoken.models import Token from django.contrib.auth.models import User @receiver(post_save, sender=User) def create_auth_token(sender, instance=None, created=False, **kwargs): if created: Token.objects.create(user=instance)
Enter fullscreen mode Exit fullscreen mode
Then, link it in tasks/apps.py:
from django.apps import AppConfigclass TasksConfig(AppConfig):default_auto_field = 'django.db.models.BigAutoField'name = 'tasks'def ready(self):import tasks.signals # Connect the signalfrom django.apps import AppConfig class TasksConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'tasks' def ready(self): import tasks.signals # Connect the signalfrom django.apps import AppConfig class TasksConfig(AppConfig): default_auto_field = 'django.db.models.BigAutoField' name = 'tasks' def ready(self): import tasks.signals # Connect the signal
Enter fullscreen mode Exit fullscreen mode
Step 3: Build Registration and Login Endpoints
Let’s give users a way to join the party (register) and get in (log in).
Create a User Serializer
In tasks/serializers.py, add:
from django.contrib.auth.models import Userfrom rest_framework import serializersclass UserSerializer(serializers.ModelSerializer):password = serializers.CharField(write_only=True, required=True)class Meta:model = Userfields = ['username', 'password']def create(self, validated_data):user = User.objects.create_user(**validated_data) # Securely hashes passwordreturn userfrom django.contrib.auth.models import User from rest_framework import serializers class UserSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True, required=True) class Meta: model = User fields = ['username', 'password'] def create(self, validated_data): user = User.objects.create_user(**validated_data) # Securely hashes password return userfrom django.contrib.auth.models import User from rest_framework import serializers class UserSerializer(serializers.ModelSerializer): password = serializers.CharField(write_only=True, required=True) class Meta: model = User fields = ['username', 'password'] def create(self, validated_data): user = User.objects.create_user(**validated_data) # Securely hashes password return user
Enter fullscreen mode Exit fullscreen mode
Add Registration and Login Views
Update tasks/views.py:
from django.contrib.auth import authenticatefrom rest_framework.authtoken.models import Tokenfrom rest_framework.response import Responsefrom rest_framework.views import APIViewfrom rest_framework import statusfrom rest_framework.permissions import AllowAnyfrom .serializers import UserSerializerclass RegisterView(APIView):permission_classes = [AllowAny] # Anyone can registerdef post(self, request):serializer = UserSerializer(data=request.data)if serializer.is_valid():user = serializer.save()token, _ = Token.objects.get_or_create(user=user)return Response({'token': token.key}, status=status.HTTP_201_CREATED)return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)class LoginView(APIView):permission_classes = [AllowAny] # Anyone can log indef post(self, request):username = request.data.get('username')password = request.data.get('password')user = authenticate(username=username, password=password)if user:token, _ = Token.objects.get_or_create(user=user)return Response({'token': token.key}, status=status.HTTP_200_OK)return Response({'error': 'Invalid Credentials'}, status=status.HTTP_400_BAD_REQUEST)from django.contrib.auth import authenticate from rest_framework.authtoken.models import Token from rest_framework.response import Response from rest_framework.views import APIView from rest_framework import status from rest_framework.permissions import AllowAny from .serializers import UserSerializer class RegisterView(APIView): permission_classes = [AllowAny] # Anyone can register def post(self, request): serializer = UserSerializer(data=request.data) if serializer.is_valid(): user = serializer.save() token, _ = Token.objects.get_or_create(user=user) return Response({'token': token.key}, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class LoginView(APIView): permission_classes = [AllowAny] # Anyone can log in def post(self, request): username = request.data.get('username') password = request.data.get('password') user = authenticate(username=username, password=password) if user: token, _ = Token.objects.get_or_create(user=user) return Response({'token': token.key}, status=status.HTTP_200_OK) return Response({'error': 'Invalid Credentials'}, status=status.HTTP_400_BAD_REQUEST)from django.contrib.auth import authenticate from rest_framework.authtoken.models import Token from rest_framework.response import Response from rest_framework.views import APIView from rest_framework import status from rest_framework.permissions import AllowAny from .serializers import UserSerializer class RegisterView(APIView): permission_classes = [AllowAny] # Anyone can register def post(self, request): serializer = UserSerializer(data=request.data) if serializer.is_valid(): user = serializer.save() token, _ = Token.objects.get_or_create(user=user) return Response({'token': token.key}, status=status.HTTP_201_CREATED) return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) class LoginView(APIView): permission_classes = [AllowAny] # Anyone can log in def post(self, request): username = request.data.get('username') password = request.data.get('password') user = authenticate(username=username, password=password) if user: token, _ = Token.objects.get_or_create(user=user) return Response({'token': token.key}, status=status.HTTP_200_OK) return Response({'error': 'Invalid Credentials'}, status=status.HTTP_400_BAD_REQUEST)
Enter fullscreen mode Exit fullscreen mode
Hook Up the URLs
In tasks/urls.py, add these routes:
from django.urls import pathfrom .views import RegisterView, LoginView, TaskListCreateView, TaskDetailViewurlpatterns = [path('register/', RegisterView.as_view(), name='register'),path('login/', LoginView.as_view(), name='login'),path('tasks/', TaskListCreateView.as_view(), name='task-list-create'),path('tasks/<int:pk>/', TaskDetailView.as_view(), name='task-detail'),]from django.urls import path from .views import RegisterView, LoginView, TaskListCreateView, TaskDetailView urlpatterns = [ path('register/', RegisterView.as_view(), name='register'), path('login/', LoginView.as_view(), name='login'), path('tasks/', TaskListCreateView.as_view(), name='task-list-create'), path('tasks/<int:pk>/', TaskDetailView.as_view(), name='task-detail'), ]from django.urls import path from .views import RegisterView, LoginView, TaskListCreateView, TaskDetailView urlpatterns = [ path('register/', RegisterView.as_view(), name='register'), path('login/', LoginView.as_view(), name='login'), path('tasks/', TaskListCreateView.as_view(), name='task-list-create'), path('tasks/<int:pk>/', TaskDetailView.as_view(), name='task-detail'), ]
Enter fullscreen mode Exit fullscreen mode
What’s this doing?
- Register: Creates a user and returns a token.
- Login: Checks credentials and hands out a token if they match.
Step 4: Secure Your Task Endpoints
Modify your TaskListCreateView
and TaskDetailView
to restrict access to authenticated users only.
Update tasks/views.py
:
from rest_framework import genericsfrom rest_framework.permissions import IsAuthenticatedfrom .models import Taskfrom .serializers import TaskSerializerclass TaskListCreateView(generics.ListCreateAPIView):queryset = Task.objects.all()serializer_class = TaskSerializerpermission_classes = [IsAuthenticated]class TaskDetailView(generics.RetrieveUpdateDestroyAPIView):queryset = Task.objects.all()serializer_class = TaskSerializerpermission_classes = [IsAuthenticated]from rest_framework import generics from rest_framework.permissions import IsAuthenticated from .models import Task from .serializers import TaskSerializer class TaskListCreateView(generics.ListCreateAPIView): queryset = Task.objects.all() serializer_class = TaskSerializer permission_classes = [IsAuthenticated] class TaskDetailView(generics.RetrieveUpdateDestroyAPIView): queryset = Task.objects.all() serializer_class = TaskSerializer permission_classes = [IsAuthenticated]from rest_framework import generics from rest_framework.permissions import IsAuthenticated from .models import Task from .serializers import TaskSerializer class TaskListCreateView(generics.ListCreateAPIView): queryset = Task.objects.all() serializer_class = TaskSerializer permission_classes = [IsAuthenticated] class TaskDetailView(generics.RetrieveUpdateDestroyAPIView): queryset = Task.objects.all() serializer_class = TaskSerializer permission_classes = [IsAuthenticated]
Enter fullscreen mode Exit fullscreen mode
Why this matters:
The IsAuthenticated
permission ensures users must send a valid token with every request—keeping your API safe from prying eyes.
Step 5: Test Your Secure API
Start your server:
python manage.py runserverpython manage.py runserverpython manage.py runserver
Enter fullscreen mode Exit fullscreen mode
We’ll use Postman to test. If you haven’t already, download it from postman.com. It’s a free, user-friendly tool for API testing.
- Open Postman and create a new request.
- Set the method to POST and the URL to
http://127.0.0.1:8000/api/register/
. - Go to the Body tab, select raw, and choose JSON from the dropdown.
Register a User
{"username" : "kihuni","password" : 1234}{ "username" : "kihuni", "password" : 1234 }{ "username" : "kihuni", "password" : 1234 }
Enter fullscreen mode Exit fullscreen mode
Log In a User
- Create a new request.
- Set method to POST and URL to
http://127.0.0.1:8000/api/login/
. - In the Body tab, use raw JSON:
{"username" : "kihuni","password" : 1234}{ "username" : "kihuni", "password" : 1234 }{ "username" : "kihuni", "password" : 1234 }
Enter fullscreen mode Exit fullscreen mode
Click Send. Expect the same token:
Add a Task
- New request:
POST to http://127.0.0.1:8000/api/tasks/
. -
In Headers, add:
Key:Authorization
Value: Tokenc80425f150f99e72553d43cfac2aaa113491de5d
(use your token) -
In Body (raw JSON):
{"title": "Myblog","description": "My first task","completed": false}{ "title": "Myblog", "description": "My first task", "completed": false }{ "title": "Myblog", "description": "My first task", "completed": false }
Enter fullscreen mode Exit fullscreen mode
Send it! You’ll see the task with an ID and timestamp.
Access Tasks
New request: Method GET, URL http://127.0.0.1:8000/api/tasks/
.
-
Headers tab:add:
Key: Authorization
Value: Tokenc80425f150f99e72553d43cfac2aaa113491de5d
(use your token) -
Click Send.
Conclusion
You’ve successfully added authentication and secured your Task Manager API. Now, only registered and authenticated users can access the API.
Summary Checklist
- Set up Django’s auth and Task model migrations
- Added DRF Token Authentication
- Built open registration/login endpoints
- Secured task endpoints
- Tested with Postman
What’s Next?
In Part 4, we’ll explore how to add user-specific tasks so that each user can only manage their tasks. Stay tuned
原文链接:How to Build a Task Manager API with Django REST Framework: Part 3 – Authentication and Permission
暂无评论内容