在 DRF 中拒绝权限时返回自定义消息

Returning custom message when a permission is denied in DRF

Django REST Framework has an excellent piece of documentation关于权限。我已经能够使用预制许可 类 并且还建立了我自己的许可。

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

在构建自定义权限 类 时,您可以 return TrueFalse - 根据文档。但如上所述,我想向用户显示更多信息。如何实现?

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

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

请参阅 http://www.django-rest-framework.org/api-guide/settings/

中的说明

从 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

来自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

它会 return 一个 dictdetail,像这样:

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

But what if you want for example that the dict key not to be detail but errors for example, it will be the same how return errors 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']
}

我在使用 DRF 3.9.4 时遇到了同样的问题。作为解决方法,我在自定义权限 class 中定义了一个简单的 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)

当未授予权限时,我将引发自定义响应的异常。 它适用于 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'

基于 Aysennoussi 的回答:

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

如果需要,您可以发送多条自定义消息。 您可以使用 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 列表中添加 class 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
}