How to Build a Task Manager API with Django REST Framework: Part 3 – Authentication and Permission

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

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 migrate
python manage.py migrate
python 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 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)
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 AppConfig
class TasksConfig(AppConfig):
default_auto_field = 'django.db.models.BigAutoField'
name = 'tasks'
def ready(self):
import tasks.signals # Connect the signal
from 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
from 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 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
from 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
from 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 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)
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 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'),
]
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 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]
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 runserver
python manage.py runserver
python 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

图片[1]-How to Build a Task Manager API with Django REST Framework: Part 3 - Authentication and Permission - 拾光赋-拾光赋
Copy the token!

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: Token c80425f150f99e72553d43cfac2aaa113491de5d(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: Token c80425f150f99e72553d43cfac2aaa113491de5d(use your token)

  • Click Send.

  • Expected: 200 OK, or your task list.

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

© 版权声明
THE END
喜欢就支持一下吧
点赞15 分享
No matter when you start, it is important not to stop after the start.
无论你在什么时候开始,重要的是开始之后就不要停止
评论 抢沙发

请登录后发表评论

    暂无评论内容