You cannot access body after reading from request's data stream while reading JSON

I am currently working on a project where users will be able to authenticate themselves thanks to a form that I protected with a CSRF token, but for now I only take care of the server side party, here is the code:

@api_view(['POST'])
@csrf_protect
@permission_classes([AllowAny])
def login(request):
    if request.method != "POST":
      return JsonResponse({"error": "Seules les requêtes POST sont autorisées."},   status=status.HTTP_405_METHOD_NOT_ALLOWED)


try:
    # Lecture sécurisée des données
    data = json.loads(request.body)
    username = data.get("username")
    password = data.get("password")

    if not username or not password:
        return JsonResponse({"error": "Nom d'utilisateur et mot de passe sont requis."}, status=status.HTTP_400_BAD_REQUEST)

    # Recherche de l'utilisateur dans les deux tables
    user = None
    role = None

    try:
        user = Administrateur.objects.get(username=username)
        role = "admin"
    except Administrateur.DoesNotExist:
        pass

    if not user:
        try:
            user = Employes.objects.get(username=username)
            role = "employe"
        except Employes.DoesNotExist:
            pass

    if not user or not check_password(password, user.password):
        return JsonResponse({"error": "Identifiants incorrects."}, status=status.HTTP_401_UNAUTHORIZED)

    # Génération des tokens
    refresh = RefreshToken.for_user(user)
    
    # Réponse sécurisée
    response = JsonResponse({"username": user.username})

   

    # Stocker le JWT dans un cookie HttpOnly sécurisé
    response.set_cookie(
        key='access_token',
        value=str(refresh.access_token),
        httponly=True,
        secure=True,
        samesite='Strict',
        max_age=3600
    )

    # Stocker le rôle pour le frontend
    response.set_cookie(
        key='user_role',
        value=role,
        httponly=False,
        secure=True,
        samesite='Strict',
        max_age=3600
    )

    return response

except Exception as e:
    return JsonResponse({"error": f"Erreur inattendue : {str(e)}"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)

The problem I encounter is when I send data with Postman to the server, it sends me this error:

{
    "error": "Erreur inattendue : You cannot access body after reading from request's data stream"
}

What I did to try to solve this error is to disable the CSRF protection, and the code works correctly, but as soon as I reactivated it this error comes back. I looked in the Django documentation, but I did not find anything about this error message.

Your issue is this line:

data = json.loads(request.body)

From the documentation:

Accessing request.POST inside middleware before the view runs or in process_view() will prevent any view running after the middleware from being able to modify the upload handlers for the request, and should normally be avoided.

The CsrfViewMiddleware class can be considered an exception, as it provides the csrf_exempt() and csrf_protect() decorators which allow views to explicitly control at what point the CSRF validation should occur. That is, in general, you can not use request.body and CsrfViewMiddleware at the same time.

You could simply use request.data since you seem to be using Django REST Framework:

https://www.django-rest-framework.org/tutorial/2-requests-and-responses/#request-objects

The core functionality of the Request object is the request.data attribute, which is similar to request.POST, but more useful for working with Web APIs.

Вернуться на верх