Django AdminSite/ModelAdmin适合普通用户使用吗?

23
并非所有的软件都需要在左侧提供给“内容制作者”使用的管理界面和右侧提供给“访问者/会员”使用的站点。
经常有人说,“管理员不是你的应用程序”(例如请参见被接受的答案(2009年3月))。
我未能在Django文档中找到这种限制的明确说明。上述观点似乎有一个潜在的假设——“一个功能强大且实用的接口,内容制作者可以立即使用它来开始向站点添加内容”,但 肯定预计了不同级别的访问权限,甚至在常见问题解答中也提到了。那么多个AdminSite实例的其他用途是什么呢?
我目前正在开发的软件主要是一个CRUD界面。每个用户都必须进行身份验证,管理用户和客户之间唯一的区别在于后者只能使用“他们”的对象(无权访问“User”等某些模型)。顺便说一下,在我的情况下,“他们”并不是指创建了该对象的人,而是指与“公司”相关联的对象
是否有任何强烈的理由不使用管理界面,只需配置正确的权限组合?ModelAdmin权限可信吗?为什么不能把所有登录的用户都称为“员工”呢?

对于传统的非管理员视图,我发现自己正在重新编写似乎已经存在的东西:ModelForm是一个不错的开始,但CRUD功能和类型相关的过滤器(包括日期下钻)并不是readily available components。管理员的功能已经提供了绝大多数最终用户所需的功能,并且字段/过滤器/模板等的自定义对我的需求来说足够了。显然,在我添加新功能的地方,例如其按钮的可见性以及访问相应视图需要权限检查。我不担心这个。我只是好奇在这种情况下管理员功能是否已经通过其内置的权限集合正确覆盖了。有任何经验吗?

更新:抱歉,这个问题的主要部分似乎不太清楚。我不担心我的自定义,我担心信任现有的管理员应用程序及其权限实现。另请参见对Daniel和FallenAngel的评论。

3个回答

12

admin 并没有什么特别的地方,它的行为跟其他视图一样。所以如果它使用权限来确定访问(例如,如果您将用户的 .is_staff 设置为 True 但只给他们访问特定权限的权限),那么它与任何其他使用权限来确定访问的视图一样安全。

同样地,您提供给 ModelAdmin 的自定义也会产生一个与您编写的任何东西一样安全的实现。

如果您为您的模型编写了自定义的 has_change_permission,例如:

def has_change_permission(self, request, obj=None):
    return obj.company == request.user.get_profile().company

这将奏效。它不仅仅是隐藏一个按钮,而是完全阻止该对象的编辑。

编写django.contrib.admin的人并没有假设任何具有is_staff = True的人都能像超级用户一样值得信任,或者愚蠢到永远不会查看网页的源代码。虽然鼓励编写自己的视图,但它仍然是一个强大的接口。

例如,请参见源代码的此部分,如果您未被授权编辑实际对象,它会引发PermissionDenied异常:

def change_view(self, request, object_id, extra_context=None):
    "The 'change' admin view for this model."
    model = self.model
    opts = model._meta

    obj = self.get_object(request, unquote(object_id))

    if not self.has_change_permission(request, obj):
        raise PermissionDenied

    # view continues...

即使有人制作了正确的 URL 来编辑给定的对象,只要你正确地实现了 has_change_permission,用户就会被拒绝访问。


1
谢谢您的回答。Apress的djangobook中描述的“管理员禅”似乎暗示了信任作为管理员“哲学”的一部分,并与经常重复的“管理员不是您的应用程序”建议配对,我感到害怕并认为Django文档可以指出预期的、可行的用例。话虽如此,我现在感觉更舒服了,很高兴能授予悬赏。不幸的是,我不能分割它,所以我会点赞FallenAngel的答案。谢谢。 - Danny W. Adair

10
我们有一个系统,按照您的要求运行。程序具有基本的用户登录功能,是基本站点,使用手写视图和模板(因为需要)。存在一个客户部分,这是带有有限访问权限的基本管理页面。还有超级管理员,就像我和像我一样的人。
逻辑是,管理员是公司中工作的人,他们可能拥有所有访问权限(正如sjango所说的超级用户),或者对应用程序有有限的访问权限,但可以查看与他们所拥有的访问权限相关的所有相关数据库记录。客户是我们销售我们的程序的人,他们对管理员有限的访问权限,并且只能查看与他们相关的记录。用户是我们客户的客户...
在这一点上,Django权限不足,因为我们的客户必须看到属于他的帐户的记录,而标准管理员可以查看所有记录。这两个用户可以根据其权限访问应用程序。超级用户可以看到和做任何事情...
为了解决这个问题,我们没有使用Django网站应用程序(我从未使用过并且没有太多信息),而是创建了一个扩展Django用户的模型,该模型具有类似于角色的字段。如果用户角色是系统管理员,则可以查看所有内容(如果是超级用户,则使用正常的权限)。否则,他只能访问与他们的网站相关的记录(在您的情况下是公司)。
因此,几乎每个数据库表都必须有一个外键,定义了相关记录的所有者公司。
通过这样做,如果需要,您可以过滤属于特定公司的记录...
在我的模型中,我有继承用户模型的Kullanici。
class Kullanici(User):
    rol = SmallIntegerField()# 1 if system admin, 2 if cusotmer etc...

然后,我编写了几种方法来覆盖管理员方法,例如; ModelAdmin.save和ModelAdmin.queryset,进行以下检查...

#override admin queryset method
def override_queryset(obj, req):
    qs = super(type(obj), obj).queryset(req)
    kullanici = Kullanici.objects.get(id=req.user.id)
    if kullanici.rol == 10:
        return qs
    return qs.filter(site=kullanici.site)

当用户进入应用程序的列表视图时,他只会看到与他相关的站点,其他记录将不会显示,或者如果他试图访问属于其他站点的记录,他将收到权限错误。这些都是基于Django的控件,因此您可以确信它们不会访问到不应访问的任何记录。

您必须覆盖所有需要过滤客户所属信息的管理方法。

为了进一步限制,我使用了一个函数来显示/隐藏模型的字段。在admin.py文件中:

class SomeModelAdmin(ModelAdmin):
    exclude= []
    def changelist_view(self, request, extra_context=None):
        extra_context = {'exclude':['field1','field2']}
        return get_admin_listview(self, request, extra_context)


def get_admin_listview(obj, req, extra):
system_admin = Kullanici.objects.get(id=req.user.id).rol == 1
if not system_admin:
    if 'exclude' in extra.keys():
        for key in extra['exclude']:
            if key not in obj.exclude:
                obj.exclude.add(key)

如果您提供一个要隐藏的字段名称列表,它将在用户不是系统管理员的情况下隐藏这些字段...

缺点是,Django管理界面的缓存可能会导致问题,我在8个月内遇到过一两次。另一个重要的部分是,您无法限制管理筛选器,因此如果您有一个需要有限访问权限的筛选器,您无法过滤筛选器键。您可以使用所有选项显示它,或者干脆不使用它。

如果这种方法解决了您的问题,我可以编写更详细的信息...

更新:是的,权限系统很简单且安全,如果您检查来自最新主干代码的permission_required装饰器的源代码...

逻辑很简单,如果用户具有相关权限,则执行相关视图。否则,相关视图或代码根本不会执行。因此,权限为Django管理提供了足够的安全性。 权限控制可以在视图级别和/或模板级别使用。

必须小心的一个问题是手写视图,其中不安全的代码可能会导致严重问题,但这完全取决于您的编码,这是您将在每个框架和编程语言上面临的安全风险...

问题的最后一点是Django和管理视图页面的过滤机制。由于几乎所有管理筛选器都使用GET来过滤数据,并将ID传递给URL以显示特定记录。 Django书的安全部分显示了可能的安全问题的基本信息以及Django如何处理它们...另一方面,2010年12月22日的安全更新显示了一个如此重要的漏洞,需要有关模型结构的足够信息。


感谢你的回答FallenAngel。我的问题不是那么关于定制管理界面(请参阅链接[3]和[4]以及我对Daniel的评论)。我想知道现有的管理界面是否适合公开使用,在多大程度上可以信任在管理应用程序中实施管理权限。 - Danny W. Adair
感谢您的回答和更新。这是一个非常有用的定制管理员的经验。Jordan的回答更接近于我的核心问题,即信任管理员(而不是权限系统),我无法分配赏金,所以我选择了点赞您的回答。谢谢。 - Danny W. Adair
谢谢您提到有关对象列表查询字符串参数的安全更新。这样的更新(引用:“具有管理员访问权限的攻击者…”)清楚地表明管理员对权限系统的实施正在不断受到审查。 - Danny W. Adair

0
如果管理员 - 如果需要,可以使用提供的钩子进行定制 - 满足您的需求,那么当然没有理由不使用它。关键是您必须对其提供和未提供的功能保持现实,并确信您不会开始需要仅在管理员外部可能实现的功能。我曾经走过这条路,那并不美好。

谢谢您的评论。我使用仅管理员(装载到 /)实现了一个相当大的应用程序。这很棒,而且我通过 urls.py 拦截添加了(相当多的)其他功能,主要是为我的自定义视图添加了一些功能(例如:具有用户可自定义和可保存过滤器/结果列的更改列表)。最大的不同点在于它是公司内部软件,所有用户都是“实际”的员工,并且完全值得信任。我想知道内置管理权限的实现是否十分牢固。例如,我不希望一个按钮只是隐藏了,但其视图仍然可以访问。 - Danny W. Adair

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接