mirror of
				https://github.com/encode/django-rest-framework.git
				synced 2025-10-31 07:57:55 +03:00 
			
		
		
		
	Merge pull request #2539 from donewell/permission-detail
add message to custom permission
This commit is contained in:
		
						commit
						8329411cc3
					
				|  | @ -190,6 +190,16 @@ 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. | ||||||
|  |      | ||||||
|  |     from rest_framework import permissions | ||||||
|  | 
 | ||||||
|  |     class CustomerAccessPermission(permissions.BasePermission): | ||||||
|  |         message = 'Adding customers not allowed.' | ||||||
|  |          | ||||||
|  |         def has_permission(self, request, view): | ||||||
|  |              ... | ||||||
|  |          | ||||||
| ## Examples | ## Examples | ||||||
| 
 | 
 | ||||||
| The following is an example of a permission class that checks the incoming request's IP address against a blacklist, and denies the request if the IP has been blacklisted. | The following is an example of a permission class that checks the incoming request's IP address against a blacklist, and denies the request if the IP has been blacklisted. | ||||||
|  |  | ||||||
|  | @ -144,13 +144,13 @@ class APIView(View): | ||||||
|         """ |         """ | ||||||
|         raise exceptions.MethodNotAllowed(request.method) |         raise exceptions.MethodNotAllowed(request.method) | ||||||
| 
 | 
 | ||||||
|     def permission_denied(self, request): |     def permission_denied(self, request, message=None): | ||||||
|         """ |         """ | ||||||
|         If request is not permitted, determine what kind of exception to raise. |         If request is not permitted, determine what kind of exception to raise. | ||||||
|         """ |         """ | ||||||
|         if not request.successful_authenticator: |         if not request.successful_authenticator: | ||||||
|             raise exceptions.NotAuthenticated() |             raise exceptions.NotAuthenticated() | ||||||
|         raise exceptions.PermissionDenied() |         raise exceptions.PermissionDenied(detail=message) | ||||||
| 
 | 
 | ||||||
|     def throttled(self, request, wait): |     def throttled(self, request, wait): | ||||||
|         """ |         """ | ||||||
|  | @ -302,7 +302,9 @@ class APIView(View): | ||||||
|         """ |         """ | ||||||
|         for permission in self.get_permissions(): |         for permission in self.get_permissions(): | ||||||
|             if not permission.has_permission(request, self): |             if not permission.has_permission(request, self): | ||||||
|                 self.permission_denied(request) |                 self.permission_denied( | ||||||
|  |                     request, message=getattr(permission, 'message', None) | ||||||
|  |                 ) | ||||||
| 
 | 
 | ||||||
|     def check_object_permissions(self, request, obj): |     def check_object_permissions(self, request, obj): | ||||||
|         """ |         """ | ||||||
|  | @ -311,7 +313,9 @@ class APIView(View): | ||||||
|         """ |         """ | ||||||
|         for permission in self.get_permissions(): |         for permission in self.get_permissions(): | ||||||
|             if not permission.has_object_permission(request, self, obj): |             if not permission.has_object_permission(request, self, obj): | ||||||
|                 self.permission_denied(request) |                 self.permission_denied( | ||||||
|  |                     request, message=getattr(permission, 'message', None) | ||||||
|  |                 ) | ||||||
| 
 | 
 | ||||||
|     def check_throttles(self, request): |     def check_throttles(self, request): | ||||||
|         """ |         """ | ||||||
|  |  | ||||||
|  | @ -376,3 +376,89 @@ class ObjectPermissionsIntegrationTests(TestCase): | ||||||
|         response = object_permissions_list_view(request) |         response = object_permissions_list_view(request) | ||||||
|         self.assertEqual(response.status_code, status.HTTP_200_OK) |         self.assertEqual(response.status_code, status.HTTP_200_OK) | ||||||
|         self.assertListEqual(response.data, []) |         self.assertListEqual(response.data, []) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class BasicPerm(permissions.BasePermission): | ||||||
|  |     def has_permission(self, request, view): | ||||||
|  |         return False | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class BasicPermWithDetail(permissions.BasePermission): | ||||||
|  |     message = 'Custom: You cannot access this resource' | ||||||
|  | 
 | ||||||
|  |     def has_permission(self, request, view): | ||||||
|  |         return False | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class BasicObjectPerm(permissions.BasePermission): | ||||||
|  |     def has_object_permission(self, request, view, obj): | ||||||
|  |         return False | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class BasicObjectPermWithDetail(permissions.BasePermission): | ||||||
|  |     message = 'Custom: You cannot access this resource' | ||||||
|  | 
 | ||||||
|  |     def has_object_permission(self, request, view, obj): | ||||||
|  |         return False | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class PermissionInstanceView(generics.RetrieveUpdateDestroyAPIView): | ||||||
|  |     queryset = BasicModel.objects.all() | ||||||
|  |     serializer_class = BasicSerializer | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class DeniedView(PermissionInstanceView): | ||||||
|  |     permission_classes = (BasicPerm,) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class DeniedViewWithDetail(PermissionInstanceView): | ||||||
|  |     permission_classes = (BasicPermWithDetail,) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class DeniedObjectView(PermissionInstanceView): | ||||||
|  |     permission_classes = (BasicObjectPerm,) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class DeniedObjectViewWithDetail(PermissionInstanceView): | ||||||
|  |     permission_classes = (BasicObjectPermWithDetail,) | ||||||
|  | 
 | ||||||
|  | denied_view = DeniedView.as_view() | ||||||
|  | 
 | ||||||
|  | denied_view_with_detail = DeniedViewWithDetail.as_view() | ||||||
|  | 
 | ||||||
|  | denied_object_view = DeniedObjectView.as_view() | ||||||
|  | 
 | ||||||
|  | denied_object_view_with_detail = DeniedObjectViewWithDetail.as_view() | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class CustomPermissionsTests(TestCase): | ||||||
|  |     def setUp(self): | ||||||
|  |         BasicModel(text='foo').save() | ||||||
|  |         User.objects.create_user('username', 'username@example.com', 'password') | ||||||
|  |         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' | ||||||
|  | 
 | ||||||
|  |     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) | ||||||
|  | 
 | ||||||
|  |     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) | ||||||
|  | 
 | ||||||
|  |     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) | ||||||
|  | 
 | ||||||
|  |     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) | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue
	
	Block a user