Search code examples
djangodjango-rest-frameworkdjango-views

Django CSRF missing or Sessions middleware required


When trying to create a django(2) rest framework api, I keep getting this error.

Forbidden (CSRF token missing or incorrect.): /login/

After doing some research the problem might be with sessions authentication which I don't really need since I will be replying on token based auth. When I try to remove some of the session auth from my settings I end up getting this.

AssertionError: The Django authentication middleware requires session middleware to be installed. Edit your MIDDLEWARE setting to insert 'django.contrib.sessions.middleware.SessionMiddleware' before 'django.contrib.auth.middleware.AuthenticationMiddleware'.

Settings.py snippet

INSTALLED_APPS = [
    # API (v1)
    'apiV1.v1.accounts.apps.AccountsConfig',

    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # Requirements
    'corsheaders',
    'rest_framework',
    'rest_framework.authtoken',
]

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.security.SecurityMiddleware',
    # 'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
]

ROOT_URLCONF = 'apiV1.urls'

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

Views.py

from django.contrib.auth import authenticate
from django.shortcuts import get_object_or_404
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from apiV1.v1.accounts.models.user import User
from apiV1.v1.accounts.serializers.user import UserSerializerLogin


# login
class LoginView(APIView):
    authentication_classes = ()
    permission_classes = ()

    @staticmethod
    def post(request):
        """
        Get user data and API token
        """

        user = get_object_or_404(User, email=request.data.get('email'))
        user = authenticate(username=user.email, password=request.data.get('password'))
        if user:
            serializer = UserSerializerLogin(user)
            return Response(serializer.data)
        return Response(status=status.HTTP_400_BAD_REQUEST)

Solution

  • If you don't need session for authentication you have to use token authentication.

    Here is the example of view

    from rest_framework.authtoken.models import Token
    from rest_framework.authtoken.views import ObtainAuthToken
    from rest_framework.response import Response
    
    class Login(ObtainAuthToken):
        def post(self, request, *args, **kwargs):
            """
            ---
            serializer: AuthTokenSerializer
            """
    
            serializer = self.serializer_class(data=request.data)
            serializer.is_valid(raise_exception=True)
            user = serializer.validated_data['user']
            token, created = Token.objects.get_or_create(user=user)
    
            return Response({
                'pk': user.pk,
                'first_name': user.first_name,
                'last_name': user.last_name,
            })
    

    Or you can use JWT authentication.

    Here are some helpful links for you.

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

    http://getblimp.github.io/django-rest-framework-jwt/