【问题标题】:Returning custom message when a permission is denied in DRF在 DRF 中拒绝权限时返回自定义消息
【发布时间】:2015-07-08 07:14:15
【问题描述】:

Django REST Framework 拥有an excellent piece of documentation 关于权限。我已经能够使用预先制作的权限类并且还构建了我自己的。

但是,在某些 API 方法中,“权限被拒绝”通用消息对用户来说信息量不是很大。例如,如果用户通过了身份验证,但帐户已过期,最好让用户知道他的帐户已过期,而不仅仅是权限被拒绝错误。

在构建自定义权限类时,您可以返回 TrueFalse - 根据文档。但是,如上所述,我想向用户显示更多信息。如何做到这一点?

【问题讨论】:

    标签: django permissions django-rest-framework


    【解决方案1】:

    从 DRF 3.2.0 开始,你只需要添加一个消息属性:

    from rest_framework import permissions
    
    class CustomerAccessPermission(permissions.BasePermission):
        message = 'Adding customers not allowed.'
    
        def has_permission(self, request, view): 
    

    参见 DRF 文档:http://www.django-rest-framework.org/api-guide/permissions/#custom-permissions

    【讨论】:

    【解决方案2】:

    来自DRF

    您可以简单地添加message 属性。

    from rest_framework import permissions
    
    class IsSuperUserPermission(permissions.BasePermission):
        message = 'User is not superuser'
    
        def has_permission(self, request, view):
            return self.request.user.is_superuser
    

    它会返回一个dict,键为detail,如下所示:

    {
        'detail': 'User is not superuser'
    }
    

    但是,如果您希望 dict 键不是 detail 而是 errors 例如,这与 return 错误 DRF 的方式相同。

    我们可以set message attribute 不是string 而是dict,像这样:

    class IsSuperUserPermission(permissions.BasePermission):
        message = {'errors': ['User is not a superuser']}
    
        def has_permission(self, request, view):
            self.message['errors'].clear()
            return self.request.user.is_superuser
    

    在这种情况下,错误将是:

    {
        'errors': ['User is not a superuser']
    }
    

    【讨论】:

    • 我一直在为我的authentication_classes 使用相同的方法,但我刚刚发现boolean 键值被转换为string。所以我在代码中设置了{"success": False, "message": "Permission denied."},实际上得到的响应是{"success": "False", "message": "Permission denied."}。有什么方法可以告诉 DRF 不要将False 转换为"False"
    【解决方案3】:

    当未授予权限时,我将引发自定义响应的异常。 它适用于 djangorestframewor(3.10.1) 和 django(2.2.3)。

    from rest_framework.permissions import BasePermission
    from rest_framework.exceptions import APIException
    from rest_framework import status
    
    
    class IsLogin(BasePermission):
        """
        Allows access only to authenticated users.
        """
    
        def has_permission(self, request, view):
            if request.email:
                return True
            raise NeedLogin()
    
    
    class NeedLogin(APIException):
        status_code = status.HTTP_403_FORBIDDEN
        default_detail = {'error': True, 'message': 'need login'}
        default_code = 'not_authenticated'
    

    【讨论】:

    • 复合权限怎么样?
    【解决方案4】:

    默认情况下,它由默认异常处理程序处理,并引发标准消息 - https://github.com/tomchristie/django-rest-framework/blob/2eb9107b875972e442ed73eef0e653fd4480d873/rest_framework/views.py#L82

    但是,您可以在 DRF 的设置中设置自己的EXCEPTION_HANDLER,并处理PermissionDenied 异常以返回您想要的消息。

    参见http://www.django-rest-framework.org/api-guide/settings/的描述

    【讨论】:

      【解决方案5】:

      我在使用 DRF 3.9.4 时遇到了同样的问题。作为一种解决方法,我在自定义权限类中只定义了一个简单的 message 属性并且它可以工作。您也可以使用 getattr 获得相同的结果。

      class IPWhitelistPermission(permissions.BasePermission):
      
          def __init__(self):
              super(IPWhitelistPermission, self).__init__()
              self._client_ip = None
      
          def has_permission(self, request, view):
              ip = get_client_ip(request)
              ret = IPWhitelist.is_whitelisted(ip)
      
              if not ret:
                  logger = logging.getLogger('access')
                  logger.warn("Unauthorized access from IP %s" % ip)
                  self._client_ip = ip
              return ret
      
          @property
          def message(self):
              return "This IP is not whitelisted [{}]".format(self._client_ip)
      

      【讨论】:

        【解决方案6】:

        以艾森努西的回答为基础:

        from rest_framework import permissions
        From django.utils import timezone
        
        class CustomerAccessPermission(permissions.BasePermission):
            message = 'Adding customers not allowed.'
        
            def has_permission(self, request, view): 
                if request.user.has_expired:
                    self.message = “Your account has expired.”
                    return False
                elif request.user.has_access:
                    return True
                else:
                    return False
        
        

        【讨论】:

          【解决方案7】:

          如果您愿意,您可以发送多个自定义消息。 您可以使用GenericAPIException 来完成。

          第 1 步:创建一个 permissions.py 文件并编写此代码。

          class Check_user_permission(permissions.BasePermission):
          def has_permission(self, request, view):
              if request.method in permissions.SAFE_METHODS:
                  return True
              else:
                  response ={
                      "success": "false",
                      'message': "Post request is not allowed for user from admin group",
                      "status_code":403,
                  }
                  raise GenericAPIException(detail=response, status_code=403)
          

          这里,response 是您要发送的 JSON 响应。

          第 2 步: 转到 view.py 文件并以这种方式在 permission_classes 列表中添加类 Check_user_permission

          class UserList(APIView):
              permission_classes = (IsAuthenticated, Check_user_permission)
              authentication_class = JSONWebTokenAuthentication
              ... 
              ...
          

          现在,如果您转到端点并发送 POST 请求,您将收到此响应。

          {
          "success": "false",
          "message": "Post request is not allowed!",
          "status_code": 403
          }
          

          【讨论】:

            猜你喜欢
            • 2021-09-17
            • 1970-01-01
            • 1970-01-01
            • 2016-03-29
            • 1970-01-01
            • 2018-11-30
            • 2018-01-09
            • 1970-01-01
            相关资源
            最近更新 更多