Reader small image

You're reading from  Building RESTful Python Web Services

Product typeBook
Published inOct 2016
Reading LevelIntermediate
PublisherPackt
ISBN-139781786462251
Edition1st Edition
Languages
Concepts
Right arrow
Author (1)
Gaston C. Hillar
Gaston C. Hillar
author image
Gaston C. Hillar

Gaston C. Hillar is Italian and has been working with computers since he was 8 years old. Gaston has a Bachelor's degree in computer science (graduated with honors) and an MBA. Currently, Gaston is an independent IT consultant and a freelance author who is always looking for new adventures anywhere in the world. He was a senior contributing editor at Dr. Dobb's, and has written more than a hundred articles on software development topics. He has received the prestigious Intel Black Belt Software Developer award eight times. He has written many articles about Java for Oracle Java Magazine. Gaston was also a former Microsoft MVP in technical computing. He lives with his wife, Vanesa, and his two sons, Kevin and Brandon.
Read more about Gaston C. Hillar

Right arrow

Chapter 3.  Improving and Adding Authentication to an API With Django

In this chapter, we will improve the RESTful API that we started in the previous chapter and also add authentication related security to it. We will:

  • Add unique constraints to the models

  • Update a single field for a resource with the PATCH method

  • Take advantage of pagination

  • Customize pagination classes

  • Understand authentication, permissions and throttling

  • Add security-related data to the models

  • Create a customized permission class for object-level permissions

  • Persist the user that makes a request

  • Configure permission policies

  • Set a default value for a new required field in migrations

  • Compose requests with the necessary authentication

  • Browse the API with authentication credentials

Adding unique constraints to the models


Our API has a few issues that we need to solve. Right now, it is possible to create many game categories with the same name. We shouldn't be able to do so, and therefore, we will make the necessary changes to the GameCategory model to add a unique constraint on the name field. We will also add a unique constraint on the name field for the Game and Player models. This way, we will learn the necessary steps to make changes to the constraints for many models and reflect the changes in the underlying database through migrations.

Make sure that you quit Django's development server. Remember that you just need to press Ctrl + C in the terminal or Command Prompt window in which it is running. Now, we will make changes to introduce unique constraints to the name field for the models that we use to represent and persist the game categories, games, and players. Open the games/models.py, file and replace the code that declares the GameCategory, Game and Player...

Updating a single field for a resource with the PATCH method


As we explained in Chapter 2, Working with Class-Based Views and Hyperlinked  APIs in Django, our API can update a single field for an existing resource, and therefore, we provide an implementation for the PATCH method. For example, we can use the PATCH method to update an existing game and set the value for its played field to true. We don't want to use the PUT method because this method is meant to replace an entire game. The PATCH method is meant to apply a delta to an existing game, and therefore, it is the appropriate method to just change the value of the played field.

Now, we will compose and send an HTTP request to update an existing game, specifically, to update the value of the played field and set it to true because we just want to update a single field, we will use the PATCH method instead of PUT. Make sure you replace 2 with the id or primary key of an existing game in your configuration:

http PATCH :8000/games/2/ played...

Taking advantage of pagination


Our database has a few rows in each of the tables that persist the models we have defined. However, after we start working with our API in a real-life production environment, we will have thousands of player scores, players, games, and game categories, and therefore, we will have to deal with large result sets. We can take advantage of the pagination features available in Django REST Framework to make it easy to specify how we want large results sets to be split into individual pages of data.

First, we will compose and send HTTP requests to create 10 games that belong to one of the categories we have created: 2D mobile arcade. This way, we will have a total of 12 games that persist in the database. We had 2 games and we will add 10 more:

http POST :8000/games/ name='Tetris Reloaded' game_category='2D mobile arcade' played=false release_date='2016-06-21T03:02:00.776594Z'
http POST :8000/games/ name='Puzzle Craft' game_category='2D mobile arcade' played=false...

Customizing pagination classes


The rest_framework.pagination.LimitOffsetPagination class that we are using to provide paginated responses declares a max_limit class attribute that defaults to None. This attribute allows us to indicate the maximum allowable limit that can be specified using the limit query parameter. With the default setting, there is no limit and we will be able to process requests that specify a value for 1000000 for the limit query parameter. We definitely don't want our API to be able to generate a response with a million player scores or players with a single request. Unluckily, there is no setting that allows us to change the value that the class assigns to the max_limit class attribute. Thus, we will create our customized version of the limit/offset pagination style provided by Django REST Framework.

Create a new Python file named pagination.py within the games folder and enter the following code which declares the new LimitOffsetPaginationWithMaxLimit class. The code...

Understanding authentication, permissions and throttling


Our current version of the API processes all the incoming requests without requiring any kind of authentication. Django REST Framework allows us to easily use different authentication schemes to identify the user that originated the request or the token that signed the request. Then, we can use these credentials to apply the permission and throttling policies that will determine whether the request must be permitted or not.

Similar to other configurations, we can set the authentication schemes globally and then override them if necessary in a class-based view or a function view. A list of classes specifies the authentication schemes. Django REST framework will use all the specified classes in the list to authenticate a request before running the code for the view. The first class in the list that generates a successful authentication, in case we specify more than one class, will be responsible for setting the values for the following...

Creating a customized permission class for object-level permissions


Create a new Python file named permissions.py within the games folder and enter the following code that, declares the new IsOwnerOrReadOnly class. The code file for the sample is included in the restful_python_chapter_03_04 folder:

from rest_framework import permissions 
 
 
class IsOwnerOrReadOnly(permissions.BasePermission): 
    def has_object_permission(self, request, view, obj): 
        if request.method in permissions.SAFE_METHODS: 
            return True 
        else: 
            return obj.owner == request.user 

The rest_framework.permissions.BasePermission class is the base class from which all permission classes should inherit. The previous lines declare the IsOwnerOrReadOnly class as a subclass of the BasePermission class and overrides the has_object_permission method defined in the superclass that returns a bool value indicating whether the permission should be granted or not. If the HTTP verb specified in...

Persisting the user that makes a request


We want to be able to list all the users and retrieve the details for a single user. We will create subclasses of the two following generic class views declared in rest_framework.generics:

  • ListAPIView: Implements the get method that retrieves a listing of a queryset

  • RetrieveAPIView: Implements the get method to retrieve a model instance

Go to the gamesapi/games folder and open the views.py file. Add the following code after the last line that declares the imports, before the declaration of the GameCategoryList class. The code file for the sample is included in the restful_python_chapter_03_04 folder:

from django.contrib.auth.models import User 
from games.serializers import UserSerializer 
from rest_framework import permissions 
from games.permissions import IsOwnerOrReadOnly 
 
 
class UserList(generics.ListAPIView): 
    queryset = User.objects.all() 
    serializer_class = UserSerializer 
    name = 'user-list' 
 
 
class UserDetail(generics.RetrieveAPIView...

Configuring permission policies


Now, we will configure permission policies for the class-based views related to games. We will override the value for the permission_classes class attribute for the GameList and GameDetail classes.

The following lines show the new code for the GameList class in the views.py file. The new lines are highlighted. Don't remove the code we added for the perform_create method for this class. The code file for the sample is included in the restful_python_chapter_03_04 folder:

class GameList(generics.ListCreateAPIView): 
    queryset = Game.objects.all() 
    serializer_class = GameSerializer 
    name = 'game-list' 
    permission_classes = ( 
        permissions.IsAuthenticatedOrReadOnly, 
        IsOwnerOrReadOnly, 
        )

The following lines show the new code for the GameDetail class in the views.py file. The new lines are highlighted. Don't remove the code we added for the perform_create method for this class. The code file for the sample is included in the...

Setting a default value for a new required field in migrations


We have persisted many games in our database and added a new owner field for the games that is a required field. We don't want to delete all the existing games, and therefore, we will take advantage of some features in Django that make it easy for us to make the changes in the underlying database without losing the existing data.

Now, we need to retrieve the id for the superuser we have created to use it as the default owner for the existing games. Django will allow us to easily update the existing games to set the owner user for them.

Run the following commands to retrieve the id from the auth_user table for the row that whose username is equal to 'superuser'. Replace superuser with the user name you selected for the previously created superuser. In addition, replace user_name in the command with the user name you used to create the PostgreSQL database and password with your chosen password for this database user. The command...

Composing requests with the necessary authentication


Now, we will compose and send an HTTP request to create a new game without authentication credentials:

http POST :8000/games/ name='The Last of Us' game_category='3D RPG' played=false release_date='2016-06-21T03:02:00.776594Z'

The following is the equivalent curl command:

curl -iX POST -H "Content-Type: application/json" -d '{"name":"The Last of Us", "game_category":"3D RPG", "played": "false", "release_date": "2016-06-21T03:02:00.776594Z"}' :8000/games/

We will receive a 401 Unauthorized status code in the response header and a detail message indicating that we didn't provide authentication credentials in the JSON body. The following lines show a sample response:

HTTP/1.0 401 Unauthorized
Allow: GET, POST, HEAD, OPTIONS
Content-Type: application/json
Date: Sun, 03 Jul 2016 22:23:07 GMT
Server: WSGIServer/0.2 CPython/3.5.1
Vary: Accept, Cookie
WWW-Authenticate: Basic realm="api"
X-Frame-Options: SAMEORIGIN
{
    "detail": "Authentication...

Browsing the API with authentication credentials


Open a web browser and enter http://localhost:8000/. Replace localhost by the IP of the computer that is running the Django development server in case you use another computer or device to run the browser. The browsable API will compose and send a GET request to / and will display the results of its execution, that is, the Api Root. You will notice that there is a Log in hyperlink in the upper-right corner.

Click Log in and the browser will display the Django REST Framework login page. Enter kevin in username, kevinpassword in password, and click Log In. Remember to replace kevin with the name you used for the user and kevinpassword with the password you configured for this user. Now, you will be logged in as kevin and all the requests you compose and send through the browsable API will use this user. You will be redirected again to the Api Root and you will notice the Log In hyperlink is replaced with the username (kevin) and a drop-down menu...

Test your knowledge


  1. Which is the most appropriate HTTP method to update a single field for an existing resource:

    1. PUT

    2. POST  

    3. PATCH

  2. Which of the following pagination classes provides a limit/offset based style in Django REST Framework:

    1. rest_framework.pagination.LimitOffsetPagination

    2. rest_framework.pagination.LimitOffsetPaging

    3. rest_framework.styles.LimitOffsetPagination

  3. The rest_framework.authentication.BasicAuthentication class:

    1. Works with Django's session framework for authentication.

    2. Provides an HTTP Basic authentication against username and password.

    3. Provides a simple token based authentication.

  4. The rest_framework.authentication.SessionAuthentication class:

    1. Works with Django's session framework for authentication.

    2. Provides an HTTP Basic authentication against username and password.

    3. Provides a simple token based authentication.

  5. The value of which of the following settings keys specify a global setting with a tuple of string whose values indicate the classes that we want to use for authentication...

Summary


In this chapter, we improved the REST API in many ways. We added unique constraints to the model and updated the database, we made it easy to update single fields with the PATCH method and we took advantage of pagination.

Then, we started working with authentication, permissions, and throttling. We added security-related data to the models and we updated the database. We made numerous changes in the different pieces of code to achieve a specific security goal and we took advantage of Django REST Framework authentication and permissions features.

Now that we have built an improved and complex API that takes into account authentication and uses permission policies, we will use additional abstractions included in the framework, we will add throttling and tests, which is what we are going to discuss in the next chapter.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
Building RESTful Python Web Services
Published in: Oct 2016Publisher: PacktISBN-13: 9781786462251
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Gaston C. Hillar

Gaston C. Hillar is Italian and has been working with computers since he was 8 years old. Gaston has a Bachelor's degree in computer science (graduated with honors) and an MBA. Currently, Gaston is an independent IT consultant and a freelance author who is always looking for new adventures anywhere in the world. He was a senior contributing editor at Dr. Dobb's, and has written more than a hundred articles on software development topics. He has received the prestigious Intel Black Belt Software Developer award eight times. He has written many articles about Java for Oracle Java Magazine. Gaston was also a former Microsoft MVP in technical computing. He lives with his wife, Vanesa, and his two sons, Kevin and Brandon.
Read more about Gaston C. Hillar