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

5
我正在为一个基于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个回答

5
回答原问题,handle_exceptiondispatch 内部被调用,所以如果你要重写 dispatch 方法,handle_exception 不会自动为你调用。但是你可以直接调用它:
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替换为相应的逻辑。

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]

同样,请确保您在rest框架设置中定义了EXCEPTION_HANDLER
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}

在这种情况下,客户端收到的响应是500。 - Ibolit
@Ibolit,你在设置中定义了Rest框架异常处理程序吗? - hspandher
我也尝试了实现.handle_exception,但是在dispatch中发生异常时它并没有被调用。 - Ibolit
@hspandler 不,我会调查一下。 - Ibolit
是的,编写一个适当的身份验证类非常有效!谢谢! - Ibolit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接