Tidy up internal view permission checking logic.

Also document correctly - these methods are now public and will fall
under the deprecation policy from now on.
This commit is contained in:
Tom Christie 2013-02-11 13:02:20 +00:00
parent 09b01887f2
commit f5a0275547
6 changed files with 20 additions and 31 deletions

View File

@ -150,7 +150,7 @@ As well as global permissions, that are run against all incoming requests, you c
# Instance must have an attribute named `owner`. # Instance must have an attribute named `owner`.
return obj.owner == request.user return obj.owner == request.user
Note that the generic views will check the appropriate object level permissions, but if you're writing your own custom views, you'll need to make sure you check the object level permission checks yourself, by calling `self.has_object_permission(request, obj)` from the view. Note that the generic views will check the appropriate object level permissions, but if you're writing your own custom views, you'll need to make sure you check the object level permission checks yourself. You can do so by calling `self.check_object_permissions(request, obj)` from the view once you have the object instance. This call will raise an appropriate `APIException` if any object-level permission checks fail, and will otherwise simply return.
[cite]: https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html [cite]: https://developer.apple.com/library/mac/#documentation/security/Conceptual/AuthenticationAndAuthorizationGuide/Authorization/Authorization.html
[authentication]: authentication.md [authentication]: authentication.md

View File

@ -76,11 +76,11 @@ The following methods are used by REST framework to instantiate the various plug
The following methods are called before dispatching to the handler method. The following methods are called before dispatching to the handler method.
### .check_permissions(...) ### .check_permissions(self, request)
### .check_throttles(...) ### .check_throttles(self, request)
### .perform_content_negotiation(...) ### .perform_content_negotiation(self, request, force=False)
## Dispatch methods ## Dispatch methods

View File

@ -131,8 +131,7 @@ class SingleObjectAPIView(SingleObjectMixin, GenericAPIView):
Override default to add support for object-level permissions. Override default to add support for object-level permissions.
""" """
obj = super(SingleObjectAPIView, self).get_object(queryset) obj = super(SingleObjectAPIView, self).get_object(queryset)
if not self.has_object_permission(self.request, obj): self.check_object_permissions(self.request, obj)
self.permission_denied(self.request)
return obj return obj

View File

@ -93,8 +93,7 @@ class UpdateModelMixin(object):
except Http404: except Http404:
# If this is a PUT-as-create operation, we need to ensure that # If this is a PUT-as-create operation, we need to ensure that
# we have relevant permissions, as if this was a POST request. # we have relevant permissions, as if this was a POST request.
if not self.has_permission(clone_request(request, 'POST')): self.check_permissions(clone_request(request, 'POST'))
self.permission_denied(self.request)
created = True created = True
success_status_code = status.HTTP_201_CREATED success_status_code = status.HTTP_201_CREATED
else: else:

View File

@ -21,8 +21,7 @@ from rest_framework.request import clone_request
from rest_framework.utils import dict2xml from rest_framework.utils import dict2xml
from rest_framework.utils import encoders from rest_framework.utils import encoders
from rest_framework.utils.breadcrumbs import get_breadcrumbs from rest_framework.utils.breadcrumbs import get_breadcrumbs
from rest_framework import VERSION, status from rest_framework import exceptions, parsers, status, VERSION
from rest_framework import parsers
class BaseRenderer(object): class BaseRenderer(object):
@ -299,12 +298,10 @@ class BrowsableAPIRenderer(BaseRenderer):
if not api_settings.FORM_METHOD_OVERRIDE: if not api_settings.FORM_METHOD_OVERRIDE:
return # Cannot use form overloading return # Cannot use form overloading
request = clone_request(request, method)
try: try:
if not view.has_permission(request): view.check_permissions(clone_request(request, method))
return # Don't have permission except exceptions.APIException:
except Exception: return False # Doesn't have permissions
return # Don't have permission and exception explicitly raise
return True return True
def serializer_to_form_fields(self, serializer): def serializer_to_form_fields(self, serializer):

View File

@ -258,33 +258,28 @@ class APIView(View):
return (renderers[0], renderers[0].media_type) return (renderers[0], renderers[0].media_type)
raise raise
def has_permission(self, request, obj=None): def check_permissions(self, request):
""" """
Return `True` if the request should be permitted. Check if the request should be permitted.
Raises an appropriate exception if the request is not permitted.
""" """
if obj is not None:
warnings.warn('The `obj` argument in `has_permission` is due to be deprecated. '
'Use `has_object_permission()` instead for object permissions.',
PendingDeprecationWarning, stacklevel=2)
return self.has_object_permission(request, obj)
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):
return False self.permission_denied(request)
return True
def has_object_permission(self, request, obj): def check_object_permissions(self, request, obj):
""" """
Return `True` if the request should be permitted for a given object. Check if the request should be permitted for a given object.
Raises an appropriate exception if the request is not permitted.
""" """
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):
return False self.permission_denied(request)
return True
def check_throttles(self, request): def check_throttles(self, request):
""" """
Check if request should be throttled. Check if request should be throttled.
Raises an appropriate exception if the request is throttled.
""" """
for throttle in self.get_throttles(): for throttle in self.get_throttles():
if not throttle.allow_request(request, self): if not throttle.allow_request(request, self):
@ -311,8 +306,7 @@ class APIView(View):
self.format_kwarg = self.get_format_suffix(**kwargs) self.format_kwarg = self.get_format_suffix(**kwargs)
# Ensure that the incoming request is permitted # Ensure that the incoming request is permitted
if not self.has_permission(request): self.check_permissions(request)
self.permission_denied(request)
self.check_throttles(request) self.check_throttles(request)
# Perform content negotiation and store the accepted info on the request # Perform content negotiation and store the accepted info on the request