Django Rest Framework - 当用户不是对象所有者时拒绝用户推送

2023-12-29

目前,我设置了权限,如果用户不是对象所有者,则可以阻止他们进行 GET、DELETE 和 PUT 操作Stock。但由于某种原因,当用户执行 PUSH 时,权限不起作用,即任何用户都可以 PUSHNote to a Stock即使他们不是Stock Owner.

为什么?我该如何正确检查User推 aNote,他们必须是所有者Stock?


这是通过以下方式发送的数据 PUSH 示例HTTPie:

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

其中“36”是现有股票的 stock_id。

这里是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()),
]

UPDATE:

根据 Tom 的回答,NoteSerializer 现在看起来像这样,这意味着用户现在只能在是 Stock 所有者的情况下推送注释(新添加的是 validate_stock 函数)。请注意,汤姆的答案和这段代码之间有一个区别:而不是仅仅检查value,我正在检查value.id。 validate_stock 函数的注释对此进行了进一步解释:

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 to v1/notes/将运行的唯一权限检查是has_permission。 URL 中没有引用任何现有实例,因此get_object没有在视图上调用,并且has_object_permissioncheck 未被调用(没有实例可以调用它。)

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

沿着这些思路的东西......

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
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Django Rest Framework - 当用户不是对象所有者时拒绝用户推送 的相关文章

  • 使用正则表达式标记化进行 NLP 词干提取和词形还原

    定义一个函数 名为performStemAndLemma 它需要一个参数 第一个参数 textcontent 是一个字符串 编辑器中给出了函数定义代码存根 执行以下指定任务 1 对给出的所有单词进行分词textcontent 该单词应包含字
  • 使用 django Rest 框架 ModelViewSet 类而不是 APIView 渲染表单

    我想使用其余框架为我的 django 模型创建样板表单 文档显示它使用 APIView http www django rest framework org topics html and forms rendering forms htt
  • 在 python 中读取具有恶意字节 0xc0 的文件,导致 utf-8 和 ascii 出错

    尝试将制表符分隔的文件读入 pandas 数据帧 gt gt gt df pd read table fn na filter False error bad lines False 它会出错 如下所示 b Skipping line 58
  • 将画布的鼠标坐标转换为地理坐标

    我正在尝试使用 Python Tkinter 创建包含意大利所有城市的地图Canvas 我在网上找到了一张意大利地图的图片 其中突出显示了一些城市 并将其插入到我的Canvas 之后 我使用一个函数来确定 2 个突出显示的城市的画布坐标 i
  • Python IF 语句到单行

    是否可以将这段代码放在一行中 if x 0 a j sum elif x 1 b j sum e e D 这不是一个仅用于演示目的的工作示例 a j sum if x 0 else b j sum 如果您有 Python 3 8 或更高版本
  • Pandas - 按每个可能的键组合聚合

    我有一个 DataFrame Pandas 我想通过 A B C 和 D 列的组合尽可能按数据进行分组 假设它具有以下形式 A B C D E F G 0 Y X Y Z 1 2 7 1 Y X Y Z 3 4 8 2 X Y U V 1
  • 如何在python中合并具有相同键的嵌套字典

    我有一个这样的数据结构 SNAPSHOT SnapshotVersion 304 SNAPSHOT SnapshotCreationDate 2015 06 21 17 33 41 CafeData CafeVersion 2807 Caf
  • 如何更改 PyGame 中声音或音乐的音量?

    如何更改 PyGame 中的音量 例如通过设置更改音量 我制作了 UI 元素 只需要知道如何更改音量即可 我知道我说不清楚 但你可以理解我 请帮忙 更改音量取决于您是否正在播放pygame mixer Sound https www pyg
  • 多行 x 刻度标签

    我正在尝试制作类似于此 Excel 示例的图 我想知道 x 刻度标签上是否有第二层 例如 5 年统计摘要 我知道我可以使用制作多行刻度标签 n但我希望能够独立地转换这两个级别 这很接近 fig plt figure figsize 8 4
  • Python 小数.InvalidOperation 错误

    当我运行这样的东西时 我总是收到此错误 from decimal import getcontext prec 30 b 2 3 Decimal b Error Traceback most recent call last File Te
  • 理解@property装饰器和继承[重复]

    这个问题在这里已经有答案了 这里是 Python 3 以防万一它很重要 我试图正确理解如何实现继承 property使用 我已经搜索了 StackOverflow 并阅读了大约 20 个类似的问题 但无济于事 因为他们试图解决的问题略有不同
  • 如何使用python读取最后一行的特定位置

    我有一个太大的 txt 文件 并且有几行类似的行 如下所示 字1 字2 字3 字4 553 75 我对位置 4 值 感兴趣 即最后一行 553 75 我的文件文本 word1 word2 word3 word4 553 20 word1 w
  • 模块“tensorflow”没有属性“random_uniform”

    我尝试执行一些深度学习应用程序 并收到模块 tensorflow 没有属性 random uniform 错误 在 CPU 上 代码运行良好 但速度非常慢 为了在 GPU 上运行代码 我需要更改一些定义 下面是我的代码 有任何想法吗 def
  • 如何向类添加对十六进制函数的支持

    我写了一个类来实现 int 方法 以便实例可以表现得像整数 class MyClass def init self value self value value def int self return self value 使用int实例上
  • 在 .vscode 中调试时遇到问题

    我最近在 VSCODE 中调试时遇到了一个大问题 我尝试通过搜索网站并重新安装一些扩展来自行修复它 而不是在中显示我的结果调试控制台它将以下输出写入我的terminal cd Users AVFL Documents Programming
  • 如何将one-hot向量转换为多标签?

    我有一项多分类任务 并且我得到了像这样的单热类型预测 0 1 1 0 1 0 1 0 1 我希望将这个单热向量转换为标签 例如 1 2 1 0 2 我已经尝试过 tf argmax 但它不起作用 那么我该如何处理呢 使用列表理解 oheLi
  • Django - 缺少 1 个必需的位置参数:'request'

    我收到错误 get indiceComercioVarejista 缺少 1 个必需的位置参数 要求 当尝试访问 get indiceComercioVarejista 方法时 我不知道这是怎么回事 views from django ht
  • SQLite 在使用之间不保存数据

    我制作了一个包含以下内容的模块 import sqlite3 as sq connection sq connect test db cursor connection cursor cursor execute DROP TABLE IF
  • Python3 类型错误:replace() 参数 1 必须是 str,而不是 int

    我已经尝试了几天让这段代码在 MacOS 上运行 但没有成功 你能看一下我错过了什么吗 运行 python 3 6 我已经上传了整个代码 多谢 usr bin env python3 from future import print fun
  • ValueError:维度 (-1) 必须在 [0, 2) 范围内

    我的python版本是3 5 2 我已经安装了keras和tensorflow 并尝试了官方的一些示例 示例链接 示例标题 用于多类 softmax 分类的多层感知器 MLP https keras io getting started s

随机推荐