Lesson 2
Implementing Sign-In and Sign-Up in Django API
Introduction to User Authentication

Welcome to the lesson on implementing Sign-In and Sign-Up functionalities in your Django application. In this lesson, we'll explore how to allow users to register and authenticate securely. This lesson builds upon our previous exploration of integrating the User model with your Todo, Group, and Tag models. We'll be leveraging the Django REST Framework (DRF) to simplify the implementation of these authentication processes.

Understanding Authentication

Authentication is the process of verifying the identity of a user or system. In the web application context, when users attempt to access a service, they must prove their identity, which is often achieved through login credentials like usernames and passwords. Once authenticated, users receive a token – a secure, encoded string that represents their session. This token is then used in subsequent requests to identify and authorize the user without needing to resend their credentials each time.

Let's dive into how we can create endpoints for Sign-In and Sign-Up, ensuring that users can effectively access and manage their accounts.

Updating Settings

Before we proceed with implementing Sign-In and Sign-Up, let's quickly make some foundational configurations. If you recall from earlier, we set up a Django project and configured it to use the Django REST Framework, which facilitates the creation of RESTful APIs. It stores a settings.py file with general project configuration. You will need to:

  1. Add 'rest_framework.authtoken' in your list of installed apps
  2. Ensure 'rest_framework.authentication.TokenAuthentication' is in the DEFAULT_AUTHENTICATION_CLASSES.
Python
1# settings.py 2INSTALLED_APPS = [ 3 ... 4 'rest_framework', 5 'rest_framework.authtoken', 6] 7 8REST_FRAMEWORK = { 9 'DEFAULT_AUTHENTICATION_CLASSES': [ 10 'rest_framework.authentication.TokenAuthentication', 11 ], 12}

This setup ensures that our Django application is ready to handle API requests using token-based authentication, a robust method for managing user sessions.

Defining the User Serializer

To create users through our API, we must define a UserSerializer, which specifies how data is converted to and from User instances. This serializer will handle user data, especially sensitive fields like passwords.

Python
1# serializers.py 2from rest_framework import serializers 3from django.contrib.auth.models import User 4 5class UserSerializer(serializers.ModelSerializer): 6 password = serializers.CharField(write_only=True) 7 8 class Meta: 9 model = User 10 fields = ['username', 'password', 'email'] 11 12 def create(self, validated_data): 13 user = User.objects.create_user( 14 username=validated_data['username'], 15 password=validated_data['password'], 16 email=validated_data.get('email') 17 ) 18 return user
  • The password field is write-only, so it won't be exposed in responses.
  • The create method customizes the user creation to handle password encryption correctly by using the create_user method, which we used in the previous unit.
Implementing the Sign-Up Process

Now, let’s implement the sign-up process, which allows new users to register themselves. To do it, we will create a generic view to handle users creation.

Python
1# views.py 2from rest_framework import generics 3from .serializers import UserSerializer 4 5class UserRegistrationView(generics.CreateAPIView): 6 serializer_class = UserSerializer
  • UserRegistrationView is a subclass of CreateAPIView, which provides the functionality to create new user objects.
  • The serializer_class specifies that UserSerializer will be used to validate and save the incoming user data.

With this setup, a client can post data to the Sign-Up endpoint to create a new user account.

Implementing the Sign-In Process

Next, let’s set up the Sign-In process, allowing users to authenticate and get a token. This time, we will inherit our view from APIView to manually define the post method.

Python
1# views.py 2from rest_framework.views import APIView 3from rest_framework.response import Response 4from rest_framework import status 5from django.contrib.auth import authenticate 6from rest_framework.authtoken.models import Token 7 8class UserLoginView(APIView): 9 def post(self, request): 10 username = request.data.get('username') 11 password = request.data.get('password') 12 user = authenticate(username=username, password=password) # Authenticate the user 13 if user is not None: 14 token, created = Token.objects.get_or_create(user=user) # Create or retrieve a token for the user 15 return Response({'token': token.key}, status=status.HTTP_200_OK) 16 return Response({'error': 'Invalid Credentials'}, status=status.HTTP_400_BAD_REQUEST)
  • The authenticate function is used to verify user credentials against the database. It checks if the supplied username and password match and returns the user instance if successful, otherwise None.
  • The Token class provides the functionality to create a token for the authenticated user. Tokens are used as a session identifier, allowing the client to authenticate future requests without resending the username and password.
  • Successful logins return a token, which clients use to authenticate future requests.
Integrating URLs for User Authentication

Let’s add URL routes to enable users to access Sign-Up and Sign-In endpoints.

Python
1# urls.py 2from django.urls import path 3from .views import UserRegistrationView, UserLoginView 4 5urlpatterns = [ 6 path('register/', UserRegistrationView.as_view(), name='register'), 7 path('login/', UserLoginView.as_view(), name='login'), 8]
  • Defines two distinct endpoints: one for registration and another for login.
  • These URLs make the authentication functionalities accessible via API requests.
Writing Tests for User Creation and Authentication

Validating that user creation and authentication are working correctly is essential. Let's incorporate tests using Django's testing framework to ensure our endpoints behave as expected.

Python
1from django.urls import reverse 2from rest_framework import status 3from rest_framework.test import APITestCase 4from django.contrib.auth.models import User 5 6class UserTests(APITestCase): 7 8 def test_register_user(self): 9 url = reverse('register') 10 data = {'username': 'testuser', 'password': 'testpass123', 'email': 'testuser@example.com'} 11 response = self.client.post(url, data, format='json') 12 self.assertEqual(response.status_code, status.HTTP_201_CREATED) 13 self.assertTrue(User.objects.filter(username='testuser').exists()) 14 15 def test_login_user(self): 16 # First, create a user 17 User.objects.create_user(username='testuser', password='testpass123') 18 19 url = reverse('login') 20 data = {'username': 'testuser', 'password': 'testpass123'} 21 response = self.client.post(url, data, format='json') 22 self.assertEqual(response.status_code, status.HTTP_200_OK) 23 self.assertIn('token', response.data)
  • test_register_user verifies the Sign-Up process. It checks that the POST request to the registration endpoint creates a user and returns a 201 Created status.
  • test_login_user checks the Sign-In endpoint. It ensures a successful login returns a 200 OK status and includes a token in the response data.
Summary and Next Steps

Congratulations on mastering the implementation of Sign-In and Sign-Up functionalities! You have learned how to use the Django REST Framework to manage user authentication, creating endpoints to securely register users and authenticate their access. This is an essential skill that bolsters the security of web applications.

As you move forward, you will have practice exercises in the next section to apply and solidify your knowledge. Feel free to experiment and explore the provided code, testing various scenarios. We are at the end of this course unit, and you've done an excellent job reaching here! Keep honing these skills to ensure your applications are robust and user-friendly. Good luck!

Enjoy this lesson? Now it's time to practice with Cosmo!
Practice is how you turn knowledge into actual skills.