Возврат пользовательского сообщения, когда в DRF отказано в разрешении
Django REST Framework имеет отличную документацию о разрешениях. Я смог использовать заранее подготовленные классы разрешений, а также создал свои собственные.
Однако существуют некоторые методы API, в которых общее сообщение "Отказано в доступе" не очень информативно для пользователя. Например, если пользователь прошел проверку подлинности, но срок действия учетной записи истек, было бы неплохо сообщить пользователю, что срок действия его учетной записи истек, а не просто ошибка отказа в разрешении.
При создании пользовательских классов разрешений вы либо возвращаете True
или же False
- согласно документации. Но я бы хотел, как сказано выше, показать пользователю более информативное сообщение. Как это сделать?
8 ответов
Начиная с 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/
От 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']
}
Когда разрешение не предоставлено, я выдам исключение, которое пользовательский ответ. Работает на 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': '请先登录'}
default_code = 'not_authenticated'
Основываясь на ответе Айсеннусси:
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
По умолчанию он обрабатывается обработчиком исключений по умолчанию и вызывает стандартное сообщение - https://github.com/tomchristie/django-rest-framework/blob/2eb9107b875972e442ed73eef0e653fd4480d873/rest_framework/views.py
Но вы можете установить собственный EXCEPTION_HANDLER
в настройках DRF, и обрабатывать 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)
Простой метод использует класс PermissionDenied и вызывает исключение:
from rest_framework.exceptions import PermissionDenied
...
if allowed:
return True
else:
# return False
raise PermissionDenied('custom message')
...
Вы можете отправить более одного персонализированного сообщения, если хотите. Вы можете сделать это, используя
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 и добавьте класс
Check_user_permission
в
permission_classes
список таким образом:
class UserList(APIView):
permission_classes = (IsAuthenticated, Check_user_permission)
authentication_class = JSONWebTokenAuthentication
...
...
Теперь, если вы перейдете к конечной точке и отправите запрос POST, вы получите этот ответ.
{
"success": "false",
"message": "Post request is not allowed!",
"status_code": 403
}