Django Rest Framework-当用户不是对象所有者时,拒绝PUSH中的用户 [英] Django Rest Framework - Deny User from PUSH when User is not Object Owner

查看:56
本文介绍了Django Rest Framework-当用户不是对象所有者时,拒绝PUSH中的用户的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

目前,我已设置权限,如果用户不是 Stock 的对象所有者,则可以阻止用户进行GET,DELETE和PUT。但是由于某些原因,当用户执行PUSH时权限不起作用,即任何用户都可以将 Note 推送到 Stock ,即使他们不是所有者

At the moment i have permissions set which prevent a user from GET, DELETE and PUT if they are not the Object Owner of Stock. But for some reason, the permissions do not work when the user performs a PUSH i.e. any user can PUSH a Note to a Stock even if they are not the Stock Owner.

为什么?以及如何正确检查用户按下注释时,他们必须是<$ c $的所有者c>股票?

Why? And how do i properly check that when a User PUSHs a Note, they must be the Owner of Stock?

这是通过 HTTPie :

http -a testuser:testpw POST http://127.0.0.1:8000/api/v1/notes/ note="Testing API" stock="36"

其中 36

这里是 stock_note / models.py

from django.db import models
from django.utils import timezone
from django.contrib.auth.models import User
import uuid

class Stock(models.Model):
    '''
    Model representing the stock info.
    '''
    user = models.ForeignKey(User)
    book_code = models.CharField(max_length=14, null=True, blank=True)

    def __str__(self):
        return self.book_code

class Note(models.Model):
    '''
    Model representing the stock note.
    '''
    user = models.ForeignKey(User)
    note = models.TextField(max_length=560)
    stock = models.ForeignKey(Stock, related_name='notes')
    date_note_created = models.DateTimeField(default=timezone.now)

    def __str__(self):
        return self.note

这是 api / serializers.py

from stock_note.models import Stock, Note
from rest_framework import serializers

class StockSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(default=serializers.CurrentUserDefault())
    notes = serializers.PrimaryKeyRelatedField(read_only=True, many=True)

    class Meta:
        model = Stock
        fields = ('id', 'user', 'book_code', 'notes')

class NoteSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(default=serializers.CurrentUserDefault())

    class Meta:
        model = Note
        fields = ('user', 'note', 'stock')

这是 api / views.py

from rest_framework import generics
from stock_note.models import Stock, Note
from api.serializers import StockSerializer, NoteSerializer
from rest_framework.permissions import IsAuthenticated
from api.permissions import IsOwner

# Create your views here.

class StockList(generics.ListCreateAPIView):
    serializer_class = StockSerializer
    permission_classes = (IsAuthenticated, IsOwner)

    def get_queryset(self):
        user = self.request.user
        return Stock.objects.filter(user=user)

    def perform_create(self, serializer):
        serializer.save()

    def perform_update(self, serializer):
        serializer.save()

class NoteList(generics.ListCreateAPIView):
    serializer_class = NoteSerializer
    permission_classes = (IsAuthenticated, IsOwner)

    def get_queryset(self):
        user = self.request.user
        return Note.objects.filter(user=user)

    def perform_create(self, serializer):
        serializer.save()

    def perform_update(self, serializer):
        serializer.save()

class StockListDetail(generics.RetrieveUpdateDestroyAPIView):
    serializer_class = StockSerializer
    permission_classes = (IsAuthenticated, IsOwner)
    lookup_url_kwarg = 'stock_id'

    def get_queryset(self):
        stock = self.kwargs['stock_id']
        return Stock.objects.filter(id=stock)

class NoteListDetail(generics.RetrieveUpdateDestroyAPIView):
    serializer_class = NoteSerializer
    permission_classes = (IsAuthenticated, IsOwner)
    lookup_url_kwarg = 'note_id'

    def get_queryset(self):
        note = self.kwargs['note_id']
        return Note.objects.filter(id=note)

这是 api / permissions.py

from rest_framework import permissions

class IsOwner(permissions.BasePermission):
    def has_permission(self, request, view):
        return request.user and request.user.is_authenticated()

    def has_object_permission(self, request, view, obj):
        return obj.user == request.user

最后是 api / urls.py

from django.conf.urls import url, include
from api import views

urlpatterns = [
    #Endpoint to allow GET and POST stocks.
    url(r'^v1/stocks/$', views.StockList.as_view()),
    #Endpoint to allow GET and POST a note to a stock.
    url(r'^v1/notes/$', views.NoteList.as_view()),
    #Endpoint to allow GET, POST, PUSH, DELETE a stocknote
    url(r'^v1/stocks/(?P<stock_id>[0-9]+)/$', views.StockListDetail.as_view()),
    #Endpoint to allow GET, POST, PUSH, DELETE a Note
    url(r'^v1/notes/(?P<note_id>[0-9]+)/$', views.NoteListDetail.as_view()),
]






更新:

接着Tom的回答,NoteSerializer现在看起来像这样,这意味着如果用户是股票的所有者,则用户现在只能推送一个便笺(新添加的是validate_stock函数)。请注意,汤姆的答案和此代码之间有一个区别:我正在检查 value.id,而不是仅检查 value 。 code>。在validate_stock函数的注释中对此进行了进一步解释:

Following on from Tom's answer the NoteSerializer now looks like this which means a User is now only able to PUSH a Note if they are the Owner of Stock (the new addition is the validate_stock function). Keep note that there is one difference between Tom's answer and this code: instead of just checking the value, i am checking for the value.id. This is explained further in the comments of the validate_stock function:

class NoteSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(default=serializers.CurrentUserDefault())

    class Meta:
        model = Note
        fields = ('user', 'note', 'stock')

    def validate_stock(self, value):
        '''
        This function checks if the User is the owner of Stock
        before allowing the User to PUSH a Note to the Stock.
        '''

        # You have to get the object ID because otherwise you get following error when
        # you try to perform Stock.object.get(...):
        #TypeError: int() argument must be a string, a bytes-like object or a number, not 'Stock'
        value_id = value.id

        stock_obj = Stock.objects.get(pk=value_id)
        user = self.context['request'].user

        if not stock_obj.user == user:
            raise serializers.ValidationError("You do not have permission to perform this action.")
        return value


推荐答案

当您 POST v1 / notes / 时,将运行的唯一权限检查是具有许可权限。 URL中没有现有实例,因此在视图上不会调用 get_object ,并且 has_object_permission check不被调用(没有实例可以调用。)

When you POST to v1/notes/ the only permission check that will run is has_permission. There's no existing instance being referred to in the URL, so get_object isn't called on the view, and the has_object_permission check isn't called (there's no instance to call it with.)

在这种情况下,您需要对序列化器类强制执行验证,以确保库存值必须与用户拥有的Stock实例相对应。

What you need for this case is to enforce validation on the serializer class that ensures that the stock value must correspond to a Stock instance that is owned by the user.

类似这些内容...

def validate_stock(self, value):
    stock = Stock.objects.get(pk=value)
    user = self.context['request'].user
    if not stock.user == user:
        raise serializers.ValidationError(...)
    return value

这篇关于Django Rest Framework-当用户不是对象所有者时,拒绝PUSH中的用户的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆