diff options
| author | Tom Christie | 2013-09-10 21:00:13 +0100 |
|---|---|---|
| committer | Tom Christie | 2013-09-10 21:00:13 +0100 |
| commit | 5970baa20112921217ae4f2c2a9f175df25922db (patch) | |
| tree | 40f4ae8e6d2ffd841c31b6a55f98d9823516d61c /rest_framework/permissions.py | |
| parent | 75fb4b02b40da04f16c6c288bbe20ea0bc0b4154 (diff) | |
| download | django-rest-framework-5970baa20112921217ae4f2c2a9f175df25922db.tar.bz2 | |
Tweaks and docs to object-level model permissions.
Diffstat (limited to 'rest_framework/permissions.py')
| -rw-r--r-- | rest_framework/permissions.py | 47 |
1 files changed, 31 insertions, 16 deletions
diff --git a/rest_framework/permissions.py b/rest_framework/permissions.py index 70bf9c61..53184798 100644 --- a/rest_framework/permissions.py +++ b/rest_framework/permissions.py @@ -152,10 +152,10 @@ class DjangoModelPermissionsOrAnonReadOnly(DjangoModelPermissions): authenticated_users_only = False -class DjangoObjectLevelModelPermissions(DjangoModelPermissions): +class DjangoObjectPermissions(DjangoModelPermissions): """ - The request is authenticated using `django.contrib.auth` permissions. - See: https://docs.djangoproject.com/en/dev/topics/auth/#permissions + The request is authenticated using Django's object-level permissions. + It requires an object-permissions-enabled backend, such as Django Guardian. It ensures that the user is authenticated, and has the appropriate `add`/`change`/`delete` permissions on the object using .has_perms. @@ -164,21 +164,22 @@ class DjangoObjectLevelModelPermissions(DjangoModelPermissions): provide a `.model` or `.queryset` attribute. """ - actions_map = { - 'GET': ['read_%(model_name)s'], - 'OPTIONS': ['read_%(model_name)s'], - 'HEAD': ['read_%(model_name)s'], - 'POST': ['add_%(model_name)s'], - 'PUT': ['change_%(model_name)s'], - 'PATCH': ['change_%(model_name)s'], - 'DELETE': ['delete_%(model_name)s'], + perms_map = { + 'GET': [], + 'OPTIONS': [], + 'HEAD': [], + 'POST': ['%(app_label)s.add_%(model_name)s'], + 'PUT': ['%(app_label)s.change_%(model_name)s'], + 'PATCH': ['%(app_label)s.change_%(model_name)s'], + 'DELETE': ['%(app_label)s.delete_%(model_name)s'], } def get_required_object_permissions(self, method, model_cls): kwargs = { + 'app_label': model_cls._meta.app_label, 'model_name': model_cls._meta.module_name } - return [perm % kwargs for perm in self.actions_map[method]] + return [perm % kwargs for perm in self.perms_map[method]] def has_object_permission(self, request, view, obj): model_cls = getattr(view, 'model', None) @@ -190,10 +191,24 @@ class DjangoObjectLevelModelPermissions(DjangoModelPermissions): perms = self.get_required_object_permissions(request.method, model_cls) user = request.user - check = user.has_perms(perms, obj) - if not check: - raise Http404 - return user.has_perms(perms, obj) + if not user.has_perms(perms, obj): + # If the user does not have permissions we need to determine if + # they have read permissions to see 403, or not, and simply see + # a 404 reponse. + + if request.method in ('GET', 'OPTIONS', 'HEAD'): + # Read permissions already checked and failed, no need + # to make another lookup. + raise Http404 + + read_perms = self.get_required_object_permissions('GET', model_cls) + if not user.has_perms(read_perms, obj): + raise Http404 + + # Has read permissions. + return False + + return True class TokenHasReadWriteScope(BasePermission): |
