【问题标题】:Django-rest-framework: return Response from .dispatchDjango-rest-framework:从 .dispatch 返回响应
【发布时间】:2018-03-24 14:15:48
【问题描述】:

我正在基于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 方法时响应上下文没有被初始化。

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

【问题讨论】:

    标签: django rest django-rest-framework


    【解决方案1】:

    为了回答最初的问题,handle_exceptiondispatch 内部被调用,因此如果您覆盖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

    【讨论】:

      【解决方案2】:

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

      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'
      }
      

      【讨论】:

      • 在这种情况下,客户端得到的响应是 500
      • @Ibolit 你有没有在设置中定义过Rest framework 异常处理程序。
      • 我也尝试过实现 .handle_exception,但它不会因为调度中的异常而被调用。
      • @hspandler 不,我会调查的。
      • 是的,编写一个适当的身份验证类很有魅力!谢谢!
      猜你喜欢
      • 2013-04-09
      • 1970-01-01
      • 2019-11-09
      • 1970-01-01
      • 2014-12-07
      • 2023-04-04
      • 1970-01-01
      • 1970-01-01
      • 2022-12-23
      相关资源
      最近更新 更多