未考虑 has_object_permission

Lin*_*nio 1 django django-rest-framework

我正在尝试使用 Django Rest Framework 强制执行权限,其中特定用户无法发布包含不是他的用户 ID 的对象。

例如,我不希望用户使用另一个 id 发布反馈。

我的模型是这样的:

class Feedback(Model):
    user = ForeignKey(User)
    ...
Run Code Online (Sandbox Code Playgroud)

我尝试对我的视图授予权限,该权限会将feedback.user.id 与request.user.id 进行比较,正确处理对象上的帖子并返回false,但它仍在发布我的对象......为什么?

风景

class FeedbackViewSet(ModelViewSet):
    model = Feedback
    permission_classes = (IsSelf,)
    serializer_class = FeedbackSerializer

    def get_queryset(self):
        ....
Run Code Online (Sandbox Code Playgroud)

许可

class IsSelf(permissions.BasePermission):

    def has_object_permission(self, request, view, obj):
        #return eval(obj.user.id) == request.user.id
        return False
Run Code Online (Sandbox Code Playgroud)

我已经注释了该行以显示问题所在。该函数再次被正确调用并返回 False,但没有引发 PermissionDenied。在此期间,我想知道这是否真的是实现这种行为的方式,如果不是,那会是什么......?谢谢。

tim*_*mop 5

Your problem is that has_object_permission is only called if you're trying to access a certain object. So on creation it is never actually used.

I'd suggest you do the check on validation. Example:

class FeedbackSerializer(HyperlinkedModelSerializer):

    def validate(self, attrs):
        user = self.context['request'].user
        if attrs['user'].id !=  user.id:
            raise ValidationError('Some exception message')
        return attrs
Run Code Online (Sandbox Code Playgroud)

If you have some other super serializer class then just change it.

Now that I think of it if the user field must always be the posting user, then you should just make that field read-only and set it on pre_save() in the viewset class.

class FeedbackViewSet(ModelViewSet):

    def pre_save(self, obj, *args, **kwargs):
        if self.action == 'create':
            obj.user = self.request.user
Run Code Online (Sandbox Code Playgroud)

And in the serializer set the user field read-only

class FeedbackSerializer(HyperlinkedModelSerializer):
    user = serializers.HyperlinkedRelatedField(view_name='user-detail', read_only=True)

    ....
Run Code Online (Sandbox Code Playgroud)