【问题标题】:How to prevent user changing URL <pk> to see other submission data Django如何防止用户更改 URL <pk> 以查看其他提交数据 Django
【发布时间】:2014-08-14 16:04:56
【问题描述】:

我是 Web 开发世界、Django 以及需要保护 URL 免受用户更改 foo/bar/pk 以访问其他用户数据的应用程序的新手。

有没有办法防止这种情况发生?或者有没有内置的方法来防止这种情况在 Django 中发生?

例如: foo/bar/22 可以更改为 foo/bar/14 并公开过去的用户数据。

我已经阅读了有关该主题的几个问题的答案,但我没有得到一个能够清晰连贯地解释这一点以及防止这种情况发生的方法的答案。我对此知之甚少,所以我不知道如何措辞这个问题来正确调查它。请像我 5 岁一样向我解释这一点。

【问题讨论】:

  • 你确实说过'ELI5'!这里的关键词是“认证”。您需要确保用户经过身份验证才能访问相关资源 (URL)。您可以使用各种装饰器、视图函数、特殊中间件等执行此操作。下面的答案是具体示例。但是“身份验证”会在 django 文档中为您指明正确的总体方向。

标签: python django model-view-controller


【解决方案1】:

有几种方法可以实现:

如果你有登录的概念,只要把网址限制为:

/foo/bar/

在代码中,user=request.user 仅显示登录用户的数据。

另一种方法是:

/foo/bar/{{request.user.id}}/

在视图中:

def myview(request, id):
    if id != request.user.id:
        HttpResponseForbidden('You cannot view what is not yours') #Or however you want to handle this

您甚至可以write a middleware 将用户重定向到他们的页面/foo/bar/userid - 如果未登录,则重定向到登录页面。

【讨论】:

  • 如何在基于类的视图的更新视图中检查这个东西?
【解决方案2】:

如果您想控制每个对象的访问,我建议您使用django-guardian。以下是配置设置和安装后的样子(来自django-guardian's docs):

>>> from django.contrib.auth.models import User
>>> boss = User.objects.create(username='Big Boss')
>>> joe = User.objects.create(username='joe')
>>> task = Task.objects.create(summary='Some job', content='', reported_by=boss)
>>> joe.has_perm('view_task', task)
False

如果您不想使用外部库,也可以使用 in Django's views

这可能是这样的:

from django.http import HttpResponseForbidden
from .models import Bar

def view_bar(request, pk):
    bar = Bar.objects.get(pk=pk)
    if not bar.user == request.user:
        return HttpResponseForbidden("You can't view this Bar.")
    # The rest of the view goes here...

【讨论】:

  • 如何在基于类的视图中执行此操作,例如更新特定条目的视图
【解决方案3】:

只需检查主键检索到的对象是否属于请求用户。在视图中,这将是

if some_object.user == request.user: ...

这要求表示对象的模型具有对 User 模型的引用。

【讨论】:

  • 这是检查用户对象和另一个用户对象——不是用户的主键。您实际上想检查somePK == request.user.id,对吗?
  • 在内部,相等性检查可能针对对象的主键字段,但这不是必需的。顺便说一下,some_object 会将 pk 传递到视图中。
  • 如何在基于类的视图的更新视图中检查这种情况?
【解决方案4】:

在我的项目中,对于多个模型/表格,用户应该只能看到他/她输入的数据,而不能看到其他用户输入的数据。对于这些模型/表,有一个用户列。

在列表视图中,这很容易实现,只需为 model.user = loggged_id.user 过滤传递给列表视图的查询集。

但是对于详细/更新/删除视图,在 URL 中看到 PK,可以想象用户可以在 URL 中编辑 PK 并访问其他用户的行/数据。

我正在使用 Django 内置的基于类的视图。

URL 中带有 PK 的视图已经具有 LoginRequiredMixin,但这并不能阻止用户更改 URL 中的 PK。

我的解决方案:“登录用户是否拥有此行 Mixin” (DoesLoggedInUserOwnThisRowMixin) -- 覆盖 get_object 方法并在那里测试。

from django.core.exceptions import PermissionDenied

class DoesLoggedInUserOwnThisRowMixin(object):

    def get_object(self):
        '''only allow owner (or superuser) to access the table row'''
        obj = super(DoesLoggedInUserOwnThisRowMixin, self).get_object()
        if self.request.user.is_superuser:
            pass
        elif obj.iUser != self.request.user:
            raise PermissionDenied(
                "Permission Denied -- that's not your record!")
        return obj

瞧!

只需将mixin放在LoginRequiredMixin之后的视图类定义行,并带有输出消息的403.html模板,就可以了。

【讨论】:

    【解决方案5】:

    在 django 中,当前登录的用户在您的视图中作为请求对象的属性 user 可用。

    这个想法是先按登录用户过滤您的模型,然后如果有任何结果,则只显示这些结果。

    如果用户试图访问不属于他们的对象,请不要显示该对象。

    解决所有这些问题的一种方法是使用 get_object_or_404 快捷功能,如果找不到与给定参数匹配的对象,则会引发 404 错误。

    使用这个,我们可以将主键和当前登录的用户传递给这个方法,如果它返回一个对象,则表示主键属于这个用户,否则它会返回一个404,就像页面没有'不存在。

    将其插入视图非常简单:

    from django.shortcuts import get_object_or_404, render
    
    from .models import YourModel
    
    def some_view(request, pk=None):
        obj = get_object_or_404(YourModel, pk=pk, user=request.user)
        return render(request, 'details.html', {'object': obj})
    

    现在,如果用户尝试使用不属于他们的 pk 访问链接,则会引发 404。

    【讨论】:

    • "当前登录的用户在您的视图中作为请求对象的属性用户可用。" -- 但请注意request.user 也可以是@987654326 @如果用户没有登录。(docs.djangoproject.com/en/dev/ref/request-response/…)
    • 404 适用于未找到的对象,不适用于不可访问的对象。
    • 如何在基于类的视图中做这件事 -> 更新视图。我在 model 的更新视图中也面临同样的问题。一个用户创建了文章,其他用户只需更改 url 即可更改它。那么我应该如何在更新视图中使用这个 get_object_or_404() 呢?
    【解决方案6】:

    您将要研究用户身份验证和授权,它们都由 [Django's Auth package] (https://docs.djangoproject.com/en/4.0/topics/auth/) 提供。两者之间也有很大的不同。

    身份验证确保某人是他们所说的人。想想,登录。你让某人填写他们的用户名和密码,以证明他们是帐户的所有者。

    授权确保某人能够访问他们试图访问的内容。因此,例如普通用户,将无法仅切换 PK。

    授权在我上面提供的链接中有详细记录。我将从那里开始并运行一些示例代码。希望这能回答你的问题。如果没有,希望它能够为您提供足够的信息,以便您回过头来提出更具体的问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-07-28
      • 1970-01-01
      • 2016-07-05
      • 1970-01-01
      • 2011-03-21
      • 2011-01-17
      • 2016-11-18
      相关资源
      最近更新 更多