HomePythonDjangoDjango Rest API – Authentication – Part5

Django Rest API – Authentication – Part5

In this part we will see about authentication for api

Django comes with a pre-build authentication framework which you can see more details here https://docs.djangoproject.com/en/2.2/topics/auth/

Even in our current project we had create one user in previous blog to test our the Browsable API

If you login to into admin system i.e http://127.0.0.1:8000/admin/ you will see “Users”, “Groups” . So django maintains full users, groups management system pre-build internally.

By default django uses “Session” and “Basic” auth which are used mainly in web based system. But for rest api’s we need “token” auth which DRF provides.

https://www.django-rest-framework.org/api-guide/authentication

Read above properly its quite self explanatory. Let’s see this in practice by creating login/registration routes

Above will require help from https://docs.djangoproject.com/en/2.2/topics/auth/default/ to understand django user object

These are code changes required, first lets setup then auth app

//settings.py

....
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.TokenAuthentication'
    )
}
....

INSTALLED_APPS = [
    ...
    'rest_framework.authtoken'
]

next on command line

$ python manage.py makemigrations
$ python manage.py migrate
$ python manage.py runserver

next lets add a route

from rest_framework.routers import DefaultRouter
from todo.views import TodoViewSet, UserAuth
from django.urls import path, include, re_path as url


"""
FULL CRUD OPERATION FOR TODO
"""
router = DefaultRouter()

"""
FULL CRUD OPERATION FOR TODO
"""
router.register(r'todo', TodoViewSet, basename='todo')

    

urlpatterns = [
    url(r'^login/$', UserAuth.as_view()),
]

urlpatterns = urlpatterns + router.urls

next let’s setup View

P.S. some import's have been missed out intentionally so that you explore official docs better and find out

class UserAuth(APIView):
    """
    Manager User Login and other things
    """
    def post(self, request):
        """
        login
        """
        user = authenticate(username=request.data.get("username"), password=request.data.get("password"))
        if user is not None:
            # A backend authenticated the credentials
            token = Token.objects.create(user=user)
            print(token.key)
            print(user)
            return Response(token.key)
        else:
            # No backend authenticated the credentials
            return Response([], status=status.HTTP_401_UNAUTHORIZED)

Now if you run this on postman you should get token

Next lets create a new route for registration

class UserRegister(APIView):
    """
    Create user 
    """

    def post(self, request):
        user = User.objects.create_user(
            username=request.data.get("username"),
            email=request.data.get("email"),
            password=request.data.get("password"))
        user.save()

        if user is not None:
            token = Token.objects.create(user=user)
            print(token.key)
            print(user)
            return Response(token.key)
        else:
            return Response([], status=status.HTTP_400_BAD_REQUEST)

Token is generated

Also in admin new user is added as well

Next let’s try to login with this same user

when we login with user getting an error

unique constraint failed: authtoken_token.user_id

This error is coming because token already exists for this user in database. So when it tries to create new token with same user_id it gives an error

If you look at the admin token already exists for users

To fix the above issue here is the updated route

class UserAuth(APIView):
    """
    Manager User Login and other things
    """

    def post(self, request):
        """
        login
        """
        user = authenticate(username=request.data.get(
            "username"), password=request.data.get("password"))
        if user is not None:
            # A backend authenticated the credentials
            try:
                token = Token.objects.get(user_id=user.id)
            except Token.DoesNotExist:
                token = Token.objects.create(user=user)
            return Response(token.key)
        else:
            # No backend authenticated the credentials
            return Response([], status=status.HTTP_401_UNAUTHORIZED)

Now, next lets add a route to fetch user data and in this we will check permission

...
from rest_framework.permissions import IsAuthenticated
...
//views.py

class UserAuth(APIView):
    """
    Manager User Login and other things
    """

    permission_classes = (IsAuthenticated,)
    def get(self, request):
        ser = UserSerializer(request.user)
        return Response(ser.data)

We need to define a UserSerializer to send back model data

//serializer.py

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = '__all__'

Rest we can add change password, update user etc as well all function details mentioned here https://docs.djangoproject.com/en/2.2/topics/auth/default/

Here is an small example of how of authentication and permission in django work with also associating a user with a snippets in case of this example so do check it
https://www.django-rest-framework.org/tutorial/4-authentication-and-permissions/

Groups/Permissions

Let’s look at user groups/permissions , till now we just looked a basic login/registration. Let’s see how we can manager groups/permission supposed we have 3 groups

  1. Admin
  2. Employee (custom group doesn’t exist)
  3. Guest (no logged)

Let’s see more about this in next blog

Leave a Reply

Your email address will not be published. Required fields are marked *

%d bloggers like this: