In this article, we'll be adding user authentication to an already existing REST API. This is a continuation of a previous article where we built a simple Bookstore Django REST API with just one endpoint that sends a response {"message": "Welcome to the BookStore!"}.
Want to Create a simple REST API with Django?
At the end of this article,
- User can register
- User can log in
- TokenBased Authentication
- User can Logout
Let's get started ๐
First, change directory into the project and spin up our environment:
$ cd bookstore
$ pipenv shell
Now, let's add some packages to our environment that will handle our authentication:
$ pipenv install django-rest-auth django-allauth
We've added some new packages, let's make our Django app aware of these authentication packages and add some functionalities too. To do this,
# ./bookstore_app/settings.py
...
INSTALLED_APPS = [
...
'rest_framework.authtoken',
'rest_auth',
'django.contrib.sites',
'allauth',
'allauth.account',
'rest_auth.registration',
]
Because Django tries to send an email e.g when a user creates an email account, we need to add a little config EMAIL_BACKEND and SITE_ID to the settings.py file. This prints the email to be sent to the console.
# ./bookstore_app/settings.py
...
INSTALLED_APPS = [
...
]
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
SITE_ID = 1
MIDDLEWARE = [
...
]
...
Next, we'll add the URLs from the rest_auth package to the project's urls.py file. This gives us access to a host of auth functionalities.
- User Registration - registration/
- User Login - login/
- User Logout - logout/
- User Details - user/
- Change Password - password/change/
- Password Reset - password/reset/
- Confirm Password Reset - password/reset/confirm/
# ./bookstore_app/urls.py
urlpatterns = [
...
path('', include('rest_auth.urls')),
path('registration/', include('rest_auth.registration.urls')),
]
After adding the URLs, let's now set some Authentication Scheme and
Permission Policies. What file are we going to be setting these?? ๐ค
NICE!!!! That will be the settings.py file. Thank you for thinking about it for me. ๐
# ./bookstore_app/settings.py
...
REST_FRAMEWORK = {
# Authentication Scheme
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.TokenAuthentication',
),
# Permission Policies
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
Now, let's run our migrations:
$ python manage.py migrate
Let's add some restrictions to the welcome viewset in the views.py file so that unauthorized users would not have access.
# ./bookstore_app/api/views.py
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
@api_view(["GET"])
@csrf_exempt
@permission_classes([IsAuthenticated])
def welcome(request):
content = {"message": "Welcome to the BookStore!"}
return JsonResponse(content)
Finally, the restriction is set and an unauthenticated user cannot have access.
Now, let's test our endpoints. We'll create a user, log in and access the welcome endpoint. You can use Postman to test with the same JSON properties, but I'll be using curl.
Registration
> Request
$ curl -X POST -H "Content-Type: application/json" -d '{"username":"testuser", "password1":"testpassword", "password2":"testpassword"}' localhost:8000/registration/
> Response:
{"key":"1565c60a136420bc733b10c4a165e07698014acb"}
Creating a user and Logging in returns a token that can be used to uniquely identify a user so we'll skip login and use the token to access the welcome endpoint that we added the restriction to.
Welcome endpoint with Token
> Request
$ curl -X GET -H 'Authorization: Token 1565c60a136420bc733b10c4a165e07698014acb' localhost:8000/api/welcome
> Response
{"message": "Welcome AH_Bookstore App!"}
Welcome endpoint without Token
> Request
$ curl -X GET -H '' localhost:8000/api/welcome
> Response
{"detail":"Authentication credentials were not provided."}
Finally, our authentication works fine. Next, we'll be adding CRUD functionality to our app and creating some models.
Thank you for reading. ๐
Top comments (3)
I know how to make a modle that only authenticated users can do GET req for it, but how to make a modle and a view where only the users who creatrd it can make GET req to it or the users that i dpesify
You can create a middleware. These are python classes that hooks into the request/response life cycle and are processed upon every request/response your Django application handles. In then you can have the logic which ascertains that the request made meets the requirements in order to receive a response.
Hey Noble, nice post. Have you faced the need to make custom serializers, according to a custom user model? How have you solved it?