[Django]-How can I use SessionAuthentication to make a login rest API with Django Rest Framework?

15👍

The /api-auth/login/ resource is only for authentication in the browseble api.
To use session authentication, you must create a session first.
You must have a login resource, which accepts user credentials and authenticates a user, using the Django authentication system.
On requesting that resource the client will get a cookie header.
The cookie and csrf token must be used in future requests.

curl -v -X POST https://example.com/api/user/login/ -d 'username=user&password=pass'

...

> Set-Cookie:  csrftoken=TqIuhp8oEP9VY32tUDcfQyUwn3cqpYCa; expires=Fri, 15-May-2015 12:48:57 GMT; Max-Age=31449600; Path=/
> Set-Cookie:  sessionid=4yb4s456lbvd974oijbdha7k3l6g52q3; expires=Fri, 30-May-2014 12:48:57 GMT; Max-Age=1209600; Path=/

DRF supports basic authentication too. You can use it to authenticate
user initially and create session. Here is an example:

from django.contrib.auth import login

from rest_framework.authentication import BasicAuthentication, SessionAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView


class MyBasicAuthentication(BasicAuthentication):

    def authenticate(self, request):
        user, _ = super(MyBasicAuthentication, self).authenticate(request)
        login(request, user)
        return user, _


class ExampleView(APIView):
    authentication_classes = (SessionAuthentication, MyBasicAuthentication)
    permission_classes = (IsAuthenticated,)

    def get(self, request, format=None):
        content = {
            'user': unicode(request.user),
            'auth': unicode(request.auth),  # None
        }
        return Response(content)
👤YAtOff

1👍

For using in android it is better to use Token Authentication.
I’ve used Session Authentication in my Django sites that are Rectified.

Here the login api is called, which stored a session id.
You can call then any other APIs.

You need to enable Session Authentication in settings

settings.py

# Rest Framework
REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': [
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ],
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema'
}

Here’s the login api (function based view):

# accounts/views.py
import json

from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import AllowAny

from django.contrib.auth import authenticate, login
from django.http import JsonResponse

@api_view(['POST',])
@permission_classes((AllowAny,))
def login_view(request):
    """
    POST API for login
    """
    data = json.loads(request.body)
    username = data.get('username')
    password = data.get('password')
    if username is None:
        return JsonResponse({
            "errors": {
                "detail": "Please enter username"
            }
        }, status=400)
    elif password is None:
        return JsonResponse({
            "errors": {
                "detail": "Please enter password"
            }
        }, status=400)

    # authentication user
    user = authenticate(username=username, password=password)
    if user is not None:
        login(request, user)
        return JsonResponse({"success": "User has been logged in"})
    return JsonResponse(
        {"errors": "Invalid credentials"},
        status=400,
    )

here is the url.py file

# accounts/urls.py
from django.urls import include, path
from .api_views import login_view

urlpatterns = [
    path('api-auth/login/', login_view, name="api-auth-login"),
]
👤ari

-2👍

If the intention is to access some endpoint by passing the username&password on the POST data, you can do the following:

urls.py

urlpatterns = [
    url(r'^stuff/', views.MyView.as_view()),
    ...
]

views.py

    from django.contrib.auth.models import User
    from rest_framework import viewsets
    from rest_framework.response import Response
    from rest_framework.views import APIView    
    from rest_framework.permissions import IsAuthenticated
    from rest_framework import exceptions
    from rest_framework import authentication
    from django.contrib.auth import authenticate, get_user_model
    from rest_framework.authentication import BasicAuthentication, 
SessionAuthentication


class ExampleAuthentication(authentication.BaseAuthentication):

    def authenticate(self, request):

        # Get the username and password
        username = request.data.get('username', None)
        password = request.data.get('password', None)

        if not username or not password:
            raise exceptions.AuthenticationFailed(_('No credentials provided.'))

        credentials = {
            get_user_model().USERNAME_FIELD: username,
            'password': password
        }

        user = authenticate(**credentials)

        if user is None:
            raise exceptions.AuthenticationFailed(_('Invalid username/password.'))

        if not user.is_active:
            raise exceptions.AuthenticationFailed(_('User inactive or deleted.'))


    return (user, None)  # authentication successful


class MyView(APIView):
    authentication_classes = (SessionAuthentication, ExampleAuthentication,)
    permission_classes = (IsAuthenticated,)

    def post(self, request, format=None):    
        content = {
            'user': unicode(request.user),
            'auth': unicode(request.auth),  # None
        }
        return Response(content)

Curl

curl -v -X POST http://localhost:8000/stuff/ -d 'username=my_username&password=my_password'

Leave a comment