dfunckt / django-rules

Awesome Django authorization, without the database

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

django-rules does not work with DjangoObjectPermissions from django rest framework

denisorehovsky opened this issue · comments

My problem is accurately described by the comment I found here https://groups.google.com/forum/#!topic/django-rest-framework/M5q6pI8vcZQ:

I have been using DjangoObjectPermissions which inherits from DjangoModelPermissions. DjangoModelPermissions has a method has_permission which checks for Model level permissions. However, if you are working with object level permissions, usually the model level permissions evaluate to false. Consequently DjangoObjectPermissions raises a permission denied.

I have easily fixed that issue be overwriting the has_permission method of DjangoObjectPermissions, but again I am wondering, have I missed anything or should that not be the default behavior of DjangoObjectPermissions.

I have a code like this:

# rules.py

import rules


############################
# Predicates
############################

@rules.predicate
def is_tweet_owner(user, tweet):
    if not tweet:
        return False
    return tweet.owner == user


############################
# Permissions
############################

rules.add_perm('tweets.add_tweet', rules.is_authenticated)
rules.add_perm('tweets.change_tweet', is_tweet_owner)
rules.add_perm('tweets.delete_tweet', is_tweet_owner)


# views.py


from rest_framework import viewsets, mixins

from .models import Tweet
from .permissions import TweetPermission
from .serializers import TweetSerializer


class TweetViewSet(mixins.CreateModelMixin,
                   mixins.DestroyModelMixin,
                   mixins.RetrieveModelMixin,
                   mixins.UpdateModelMixin,
                   viewsets.GenericViewSet):
    queryset = Tweet.objects.all()
    serializer_class = TweetSerializer
    permission_classes = (TweetPermission, )

    def perform_create(self, serializer):
        serializer.save(owner=self.request.user)


# permissions.py


from rest_framework import permissions


class TweetPermission(permissions.DjangoObjectPermissions):
    authenticated_users_only = False

    def has_permission(self, request, view):
        """
        WTF?!
        """
        return True

I want the tweet can be updated or deleted only by the user that owns this tweet. But user.has_perms method will always return false, because django calls has_permission method before has_object_permission.

So, django will call this:

>>> user.has_perms(['tweets.change_tweet'])
False

But I want this:

>>> user.has_perms(['tweets.change_tweet'], tweet)
True

I think you should create an issue with DRF, I don't see what this has to do with django-rules. Reopen if you think I'm mistaken.