Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/django/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Django Tastypie中ForeignKey使用POST的问题_Django_Api_Tastypie - Fatal编程技术网

Django Tastypie中ForeignKey使用POST的问题

Django Tastypie中ForeignKey使用POST的问题,django,api,tastypie,Django,Api,Tastypie,我正在使用django tastypie构建一个简单的API。我的想法是我有两个资源: 表示用户留下的注释的注释资源。只有创建注释的用户才能对其进行编辑 评论资源。任何用户都可以在任何注释上留下注释 TL;DR:我无法将注释编辑限制在注释的创建者,同时仍允许任何用户对注释进行评论 我正在使用以下设置进行身份验证: class CreatedByEditAuthorization(Authorization): def is_authorized(self, request, obje

我正在使用django tastypie构建一个简单的API。我的想法是我有两个资源:

  • 表示用户留下的注释的注释资源。只有创建注释的用户才能对其进行编辑
  • 评论资源。任何用户都可以在任何注释上留下注释
TL;DR:我无法将注释编辑限制在注释的创建者,同时仍允许任何用户对注释进行评论

我正在使用以下设置进行身份验证:

class CreatedByEditAuthorization(Authorization):
    def is_authorized(self, request, object=None, **kwargs):
        return True

    def apply_limits(self, request, object_list):
        if request and request.method != 'GET' and hasattr(request, 'user'):
            return object_list.filter(created_by=request.user)
        return object_list
简而言之,用户仅被授权编辑其与created_by属性相等的对象(他们只能编辑其创建的对象)

链接如下:

class NoteResource(ModelResource):
    comments = fields.ToManyField('myapp.api.resources.CommentResource', 'comments', null=True, blank=True)
    created_by = fields.ToOneField('account.api.resources.UserResource', 'created_by')

    def obj_create(self, bundle, request, **kwargs):
        return super(HapResource, self).obj_create(bundle, request, created_by=request.user)

    class Meta:
        queryset = Note.objects.all()
        allowed_methods = ['get', 'put', 'post']
        authorization = CreatedByEditAuthorization()
因此,在这里,当创建对象时,我会自动将当前用户附加到由创建的
属性,并将其链接到适当的授权

注释
资源很简单,只有一个
外键
注释
资源

问题在于:如果用户A创建了一个便笺,而用户B试图对该便笺发表评论,则tastypie会发送(或模拟)一个POST请求来编辑该便笺。该尝试被拒绝,因为用户B没有创建注释,因此创建注释失败

问题是:有没有办法:

  • 防止tastypie使用POST创建与便笺资源的反向关系或
  • 更改授权方案,使便笺只能由其创建者编辑,但通常可以创建注释
  • 提前感谢您提供的任何见解

    编辑: 我有一个大的胖黑客可以做到这一点。我相当肯定它是安全的,但我不能肯定;我将尝试构造一些查询以确保。我创建了一个自定义字段,而不是在
    注释中使用
    字段。ForeignKey
    注释相关:

    class SafeForeignKey(fields.ForeignKey):
        def build_related_resource(self, value, request=None, related_obj=None, related_name=None):
            temp = request.method
            if isinstance(value, basestring):
                request.method = 'GET'
            ret = super(SafeForeignKey, self).build_related_resource(value, request, related_obj, related_name)
            request.method = temp
            return ret
    
    每次尝试构造此相关资源时,我们都将请求标记为
    GET
    (因为我们希望它与
    SELECT
    查询匹配,而不是与
    PUT
    POST
    匹配的
    UPDATE
    )。如果使用不当,这真的很难看,而且可能不安全,我希望有更好的解决方案


    编辑2:从读取tastypie源,据我所知,没有办法通过实际发送的查询过滤授权。

    一个简单的解决方案应该是在
    apply\u限制
    内检查请求是否为注释资源或注释资源。e、 差不多

    def apply_limits(self, request, object_list):
        if request and request.method != 'GET' and hasattr(request, 'user') and getattr(request, 'path','').startswith('/api/v1/note'):
            return object_list.filter(created_by=request.user)
        return object_list
    
    然后,当用户直接访问注释资源,而不是通过其他相关资源(如注释)时,您只限制同一用户访问注释

    更新:或者更安全的方法是检查请求是否以“api/v1/comment”开头,而不是以“note”开头。然而,同样的原则也适用。在对请求路径进行这种基于文本的比较时要小心,以避免出现有人简单地在url中添加字符串以绕过您的授权的情况。希望预结束更加有限,因为它需要在url.py中找到正确的url,因此我在这里使用了
    startswith
    。当然,您必须调整路径字符串以匹配您的tastypie URL。

    根据以下讨论:

    确定是否可以更新
    资源
    的方法是
    可以更新
    。因此,要以“正确”的方式进行此操作,您需要创建
    NoteResource
    的子类:

    class SafeNoteResource(NoteResource):
        def can_update(self):
            return False
        class Meta:
            queryset = Note.objects.all()
            allowed_methods = ['get']
            authorization = Authorization()
            # You MUST set this to the same resource_name as NoteResource
            resource_name = 'note'
    

    然后让
    CommentResource
    以标准方式链接到注释:
    note=fields.ForeignKey(SafeNoteResource,'note')
    两个问题-您是否使用contrib.comments?您正在使用身份验证和授权吗?我有一个非常类似的设置(没有seem CommentResource),在另一个用户对象上发布新评论时效果很好。@JamesO没有,我们的评论比contrib.comments提供的要丰富一些(还有其他与具有相同问题的帖子相关联的数据)。我们目前只使用内置身份验证()(即每个人都经过身份验证)。您是否已将此作为问题发布到django tastypie:?如果每次您创建与父记录相关的内容时,它都真正尝试更新父记录,这更像是一个bug,而不是一个功能。@JordanReiter see-tastypie似乎保存了所有相关字段,甚至有评论说它只是“以防万一”。@Yoav我们知道是否有必要调用save_related?这似乎是一个比我建议的更大的攻击;对于相应的
    资源
    ,应在
    Meta
    中处理表级权限。此外,正如您所说,基于文本的比较可能是危险的(事实上,如果您与
    full=True
    ——在这种情况下,URL可能不包含/comment/)的注释有关联,也会导致错误)。从捆绑包传递回来的内容的意义上讲,您是对的,路径实际上是您拥有的唯一相关数据。不确定我的建议比将请求方法从POST更改为GET(更不用说添加的代码行)更严重。在我提出的解决方案中,授权被处理在正确的位置(即apply_limits),并且无论full=True与否,都可以执行url检查。我们正在检查请求URL,而不是任何捆绑数据。我的解决方案也许可以通过在Comments资源obj_create内的request对象中添加某种标志,然后在Notes apply_limits方法中检查它来改进一点。这是一个更大的缺陷,因为它破坏了模块化。表级授权应在