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



>Django REST 框架有一个关于权限的优秀文档。我已经能够使用预制的权限类,并且还构建了自己的权限类。

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

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

从 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

它将返回一个带有密钥detail dict,如下所示:

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

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

默认情况下,它由默认异常处理程序处理,并且它正在引发标准消息 - 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/中的说明

我在使用 DRF 3.9.4 时遇到了同样的问题。作为一种解决方法,我在自定义权限类中只定义了一个简单的消息属性,它可以工作。你也可以使用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)

如果需要,您可以发送多个自定义消息。您可以使用 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
}

最新更新