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

Ibo*_*lit 5 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,
        )
Run Code Online (Sandbox Code Playgroud)

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

有没有一种更合适的方法呢?

hsp*_*her 5

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

from rest_framework.exceptions import PermissionDenied

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

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

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]
Run Code Online (Sandbox Code Playgroud)

还要确保您已EXCEPTION_HANDLER在其余框架设置中进行了定义。

REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}
Run Code Online (Sandbox Code Playgroud)


Aar*_*lin 5

要回答原始问题,handle_exception请在 inside 中调用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
Run Code Online (Sandbox Code Playgroud)

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