Django-rest-framework:从.dispatch返回响应

时间:2017-10-12 15:08:07

标签: django rest django-rest-framework

我在基于django-rest-framework的应用程序中进行(或多或少)自定义身份验证,我只需要调用另一个微服务来询问令牌是否有效以及与哪个用户名/用户ID相关联用它。 (我没有为用户提供本地表格。)

找不到开箱即用的解决方案,我正在覆盖dispatch方法(我正在使用基于APIView的视图),在那里我向远程服务发出请求,如果响应不是200,我想返回403错误。

这是我的代码:

def dispatch(self, request, *args, **kwargs):
    try:
        user_info = user_from_token_in_request(request)
        return super().dispatch(*args, **kwargs)
    except:
        return Response(
            "No Auth Token provided or bad Auth Token"
            status.HTTP_403_FORBIDDEN,
        )

但是,当我传递无效令牌时,我收到此错误:AssertionError: .accepted_renderer not set on Response,因为在处理dispatch方法时未初始化响应上下文。

有没有更合适的方法呢?

2 个答案:

答案 0 :(得分:4)

而不是返回Response尝试引发DRF提供的异常之一,而异常处理程序将自动处理其余的异常。

from rest_framework.exceptions import PermissionDenied

def dispatch(self, request, *args, **kwargs):
    try:
        # ...
    except:
        raise PermissionDenied("NO Auth Token provided")

话虽如此,建议不要在您的视图中编写您的身份验证代码。您应该在自定义身份验证/权限类中完成此操作。

from rest_framework.authentication import BaseAuthentication

class MyAuthentication(BaseAuthentication):
    def authenticate(self, request):
        try:
            user_info = user_from_token_in_request(request)
        except:
            raise AuthenticationFailed('No auth token provided')

class MyApiView(APIView):
    authentication_classes = [MyAuthentication]

另外请确保您已在休息框架设置中定义了EXCEPTION_HANDLER

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}

答案 1 :(得分:2)

要回答原始问题,在handle_exception内部调用dispatch,因此,如果您要覆盖dispatch,将不会自动为您调用。但是您可以直接调用它:

from rest_framework.exceptions import PermissionDenied

class SometimesErrorMixin:
    should_error = None

    def dispatch(self, request, *args, **kwargs):

        if not self.should_error:
            return super().dispatch(request, *args, **kwargs)

        # Lifted from DRF
        self.args = args
        self.kwargs = kwargs
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        response = self.handle_exception(PermissionDenied())
        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response

将此Mixin放在ViewSet的最左侧以使用该行为。显然,您可以使用适当的逻辑替换should_error