Как заблокировать авторизацию пользователя для Django Rest Framework в пользовательском Middleware?

Здравствуйте, я создаю пользовательское промежуточное ПО в Django для DRF.

Чтобы при попытке пользователя получить доступ к любому из api промежуточное ПО выполняло некоторую операцию и определяло, авторизован ли пользователь для доступа к конечной точке или нет.

Мой код выглядит следующим образом:

class PermissionMiddleware(MiddlewareMixin):
    def process_view(self, request, view_func, view_args, view_kwargs):
        if request.path.startswith('/admin/'):
            return None


        if request.path.startswith('/api/'):
            is_allowed = True
            if not is_allowed:
                return # < -- What needs to return to block the access
            return None

Моя проблема в том, что я должен вернуть из метода для запрета доступа к api? Я могу вернуть None, если я хочу дать доступ. Но я хочу запретить доступ и вернуть некоторое сообщение из представления api, чтобы пользователь знал, что ему не разрешено.

Итак, вкратце:

  1. Что я должен вернуть из промежуточного ПО, чтобы заблокировать доступ?
  2. Как вернуть пользователю сообщение о том, что он не авторизован?

Спасибо

Я думаю, вы бы подняли

PermissionDenied

Ошибка, и это будет обработано соответствующим образом.

Эта ошибка будет обработана следующим образом:

https://docs.djangoproject.com/en/4.1/topics/http/middleware/#process-exception

Допустим, вы хотите ограничить доступ к вашей конечной точке.

  1. Для достижения этого у вас есть два метода представления:
    check_permissions - принимает решение о том, разрешен ли запрос и пользователь разрешено ли продолжить. check_object_permissions - принимает решение о том, разрешено ли пользователю взаимодействовать с объектом.
  2. Чтобы определить свою собственную логику валидации, вы можете подкласс BasePermission класс из rest_framework:
    class YourCustomPermission(permissions.BasePermission):
    
        # Will be retrieved from the view's methods mentioned above
        custom_message = 'Your message.'
    
        def has_permission(self, request, view):
            if is_your_custom_request_logic_satisfied(request):
                return True
            return False
    
        def has_object_permission(self, request, view, obj):
            if is_your_custom_object_logic_satisfied(request, obj):
                return True
            return False 
    
  3. И, наконец, ваше представление:
    class APIView(View):
        ...
        permission_classes = [IsAuthenticated, YourCustomPermission]
    
        def check_permissions(self, request):
            for permission in self.get_permissions():
                if not permission.has_permission(request, self):
                    self.permission_denied(
                        request,
                        message=getattr(permission, 'custom_message', None),
                        code=getattr(permission, 'code', None)
                    )
    
        def check_object_permissions(self, request, obj):
            for permission in self.get_permissions():
                if not permission.has_object_permission(request, self, obj):
                    self.permission_denied(
                        request,
                        message=getattr(permission, 'custom_message', None),
                        code=getattr(permission, 'code', None)
                    )
    

Вот хороший учебник для чтения.

Этот подход я использовал для получения ожидаемого результата. Таким образом, мне не нужно изменять представление api. Надеюсь, это поможет другим в будущем.

from django.http import JsonResponse


class PermissionMiddleware(MiddlewareMixin):
    def process_view(self, request, view_func, view_args, view_kwargs):
        if request.path.startswith('/admin/'):
            return None


        if request.path.startswith('/api/'):
            is_allowed = True
            if not is_allowed:
                return JsonResponse(
                    {"detail": "Subscription Expired or Not Subscribed"}, 
                     status=403
                )
            return None
Вернуться на верх