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?