Pass custom code to PermissionDenied if permission class had one set (#7306)

This commit is contained in:
Mathieu Pillard 2020-05-01 11:22:36 +02:00 committed by GitHub
parent 4349ce1a54
commit d7777ea10f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 16 additions and 5 deletions

View File

@ -231,7 +231,7 @@ If you need to test if a request is a read operation or a write operation, you s
---
Custom permissions will raise a `PermissionDenied` exception if the test fails. To change the error message associated with the exception, implement a `message` attribute directly on your custom permission. Otherwise the `default_detail` attribute from `PermissionDenied` will be used.
Custom permissions will raise a `PermissionDenied` exception if the test fails. To change the error message associated with the exception, implement a `message` attribute directly on your custom permission. Otherwise the `default_detail` attribute from `PermissionDenied` will be used. Similarly, to change the code identifier associated with the exception, implement a `code` attribute directly on your custom permission - otherwise the `default_code` attribute from `PermissionDenied` will be used.
from rest_framework import permissions

View File

@ -166,13 +166,13 @@ class APIView(View):
"""
raise exceptions.MethodNotAllowed(request.method)
def permission_denied(self, request, message=None):
def permission_denied(self, request, message=None, code=None):
"""
If request is not permitted, determine what kind of exception to raise.
"""
if request.authenticators and not request.successful_authenticator:
raise exceptions.NotAuthenticated()
raise exceptions.PermissionDenied(detail=message)
raise exceptions.PermissionDenied(detail=message, code=code)
def throttled(self, request, wait):
"""
@ -331,7 +331,9 @@ class APIView(View):
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request, message=getattr(permission, 'message', None)
request,
message=getattr(permission, 'message', None),
code=getattr(permission, 'code', None)
)
def check_object_permissions(self, request, obj):
@ -342,7 +344,9 @@ class APIView(View):
for permission in self.get_permissions():
if not permission.has_object_permission(request, self, obj):
self.permission_denied(
request, message=getattr(permission, 'message', None)
request,
message=getattr(permission, 'message', None),
code=getattr(permission, 'code', None)
)
def check_throttles(self, request):

View File

@ -438,6 +438,7 @@ class BasicPerm(permissions.BasePermission):
class BasicPermWithDetail(permissions.BasePermission):
message = 'Custom: You cannot access this resource'
code = 'permission_denied_custom'
def has_permission(self, request, view):
return False
@ -450,6 +451,7 @@ class BasicObjectPerm(permissions.BasePermission):
class BasicObjectPermWithDetail(permissions.BasePermission):
message = 'Custom: You cannot access this resource'
code = 'permission_denied_custom'
def has_object_permission(self, request, view, obj):
return False
@ -492,30 +494,35 @@ class CustomPermissionsTests(TestCase):
credentials = basic_auth_header('username', 'password')
self.request = factory.get('/1', format='json', HTTP_AUTHORIZATION=credentials)
self.custom_message = 'Custom: You cannot access this resource'
self.custom_code = 'permission_denied_custom'
def test_permission_denied(self):
response = denied_view(self.request, pk=1)
detail = response.data.get('detail')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertNotEqual(detail, self.custom_message)
self.assertNotEqual(detail.code, self.custom_code)
def test_permission_denied_with_custom_detail(self):
response = denied_view_with_detail(self.request, pk=1)
detail = response.data.get('detail')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertEqual(detail, self.custom_message)
self.assertEqual(detail.code, self.custom_code)
def test_permission_denied_for_object(self):
response = denied_object_view(self.request, pk=1)
detail = response.data.get('detail')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertNotEqual(detail, self.custom_message)
self.assertNotEqual(detail.code, self.custom_code)
def test_permission_denied_for_object_with_custom_detail(self):
response = denied_object_view_with_detail(self.request, pk=1)
detail = response.data.get('detail')
self.assertEqual(response.status_code, status.HTTP_403_FORBIDDEN)
self.assertEqual(detail, self.custom_message)
self.assertEqual(detail.code, self.custom_code)
class PermissionsCompositionTests(TestCase):