В MiddlewareMixin.__init__() отсутствует 1 необходимый позиционный аргумент: 'get_response'

Я создал пользовательское промежуточное ПО django и декоратор для аутентификации RESTful API, который я разрабатываю. Вот код промежуточного ПО, которое я разработал:

# myproject/middleware.py

import jwt
from django.conf import settings
from django.http import JsonResponse
from users.models import User

class JWTAuthenticationMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        excluded_paths = ['/auth/users/register/', '/auth/users/login/']

        if any(request.path.startswith(path) for path in excluded_paths):
            return self.get_response(request)  # Skip JWT validation for excluded paths

        token = request.COOKIES.get('jwt')
        if token:
            try:
                decoded = jwt.decode(token, settings.SECRET_KEY, algorithms=["HS256"])
                user = User.objects.get(id=decoded['id'])
                request.user = user
            except (jwt.ExpiredSignatureError, jwt.InvalidTokenError, User.DoesNotExist):
                return JsonResponse({'error': 'Invalid or expired token'}, status=401)
        else:
            request.user = None

        return self.get_response(request)

Вот код для декоратора:

# users/utils.py

from functools import wraps
from django.http import JsonResponse
from django.middleware.csrf import CsrfViewMiddleware

def token_required(view_func):
    @wraps(view_func)
    def _wrapped_view(view_class_instance, request, *args, **kwargs):
        csrf_middleware = CsrfViewMiddleware()

        # Check CSRF token
        csrf_error = csrf_middleware.process_view(request, None, (), {})
        if csrf_error:
            return csrf_error

        if not request.user:
            return JsonResponse({'error': 'Token is missing or invalid'}, status=401)

        return view_func(view_class_instance, request, *args, **kwargs)
    return _wrapped_view

Вот один из видов, который выдает ошибку:

from rest_framework.views import APIView
from users.serializers import UserSerializer
from rest_framework.response import Response
from users.models import User
from rest_framework.exceptions import AuthenticationFailed
import jwt
from django.conf import settings
from users.utils import token_required

class UserView(APIView):
    @token_required
    def get(self, request):
        token = request.COOKIES.get('jwt')

        if not token:
            raise AuthenticationFailed('Unauthenticated User!')

        try:
            payload = jwt.decode(token, settings.SECRET_KEY, algorithms=['HS256'])
        except jwt.ExpiredSignatureError:
            raise AuthenticationFailed("Token has expired! Login again")

        user = User.objects.filter(id=payload['id']).first()
        serializer = UserSerializer(user)
        return Response(serializer.data)

А ошибка следующая:

MiddlewareMixin.init() missing 1 required positional argument: 'get_response'

Мне очень нужна помощь в том, чтобы заставить это работать. Версии Python и Django, которые я использую, - 3.12.3 и 5.0.4 соответственно.

Я перепробовал множество различных решений, но ни одно из них пока не помогло. Даже ChatGPT не может найти проблемы в этом маленьком кусочке кода.

Проблема не в классе JWTAuthenticationMiddleware, который вы определили. Скорее всего, ошибка вызвана классом CsrfViewMiddleware в вашем декораторе.

В Django 2.x и более поздних версиях классы промежуточного ПО должны инициализироваться параметром get_response. Класс CsrfViewMiddleware - это встроенный в Django класс middleware, который также подчиняется этому правилу. Однако вы не передаете параметр get_response при инициализации класса CsrfViewMiddleware.

Один из способов исправить это - использовать атрибут get_response из объекта request для инициализации класса CsrfViewMiddleware. Однако этот процесс не так прост и может работать не так, как ожидалось.

Лучшим подходом будет использование встроенного в Django декоратора csrf_exempt или декоратора csrf_protect для обработки проверки токенов CSRF.

Вот как можно изменить декоратор, чтобы он использовал csrf_exempt:

from django.views.decorators.csrf import csrf_exempt

def token_required(view_func):
    @wraps(view_func)
    def _wrapped_view(view_class_instance, request, *args, **kwargs):
        if not request.user:
            return JsonResponse({'error': 'Token is missing or invalid'}, status=401)

        return csrf_exempt(view_func)(view_class_instance, request, *args, **kwargs)
    return _wrapped_view

Однако использование csrf_exempt отключит защиту CSRF для представления, что может быть нежелательно. Если вы хотите сохранить защиту от CSRF, вместо нее можно использовать декоратор csrf_protect:

from django.views.decorators.csrf import csrf_protect

def token_required(view_func):
    @wraps(view_func)
    def _wrapped_view(view_class_instance, request, *args, **kwargs):
        if not request.user:
            return JsonResponse({'error': 'Token is missing or invalid'}, status=401)

        return csrf_protect(view_func)(view_class_instance, request, *args, **kwargs)
    return _wrapped_view

Не забудьте удалить из декоратора инициализацию csrf_middleware и проверку токена CSRF.

Кроме того, обратите внимание, что Django Rest Framework (DRF) имеет встроенную поддержку аутентификации JWT и защиты CSRF. Возможно, вы захотите использовать встроенные функции DRF вместо того, чтобы создавать собственное решение.

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