最终用户的Django AdminSite / ModelAdmin?

时间:2011-04-03 19:21:13

标签: django permissions admin

并非所有软件都需要左侧“内容制作者”的管理界面和右侧“访客/成员”的网站。

通常会说“管理员不是您的应用”(例如参见the accepted answer (March 2009))。

我无法在Django文档中找到这样的限制。 上面似乎有一个潜在的假设 - “a powerful and production-ready interface that content producers can immediately use to start adding content to the site” - 但是different levels of access are certainly anticipated, even mentioned in the FAQ。还有多个AdminSite实例的其他用例呢?

我目前正在开发一款主要是CRUD界面的软件。每个用户都必须经过身份验证,管理员用户和客户之间的唯一区别是后者只能使用“他们的”对象(并且无法访问某些模型,如“用户”等)。 By the way "their" in my case not related to who created the object, but rather which "Company" its associated with

有没有令人信服的理由不坚持使用管理界面,只是配置正确的权限鸡尾酒? ModelAdmin权限可以信任吗?为什么不调用所有登录用户“工作人员”?

对于传统的非管理员视图,我发现自己正在重写已经存在的东西:ModelForm是一个不错的开始,但CRUD功能和类型相关的过滤器(包括日期深入分析)并不容易获得组件。 Admin的功能已经提供了最终用户所需的绝大多数功能,并且字段/过滤器/模板等的自定义足以满足我的需求。显然我在哪里添加了一个新功能,例如其按钮的可见性和对相应视图的访问需要权限检查。我并不担心。我只是好奇是否在这样的情况下,管理功能被其内置的权限集正确覆盖。有这方面的经验吗?

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

3 个答案:

答案 0 :(得分:10)

我们有一个系统可以按你的要求运行。

程序有一个基本的用户登录,这是基本的网站,并使用手写的视图和模板(因为它需要)...存在客户 part,这是具有有限访问权限的基本管理页面。并且 admin 是我和像我这样的人。

逻辑是,管理员是在公司工作的人,可能拥有所有访问权限(sjango所说的超级用户)或对应用程序的有限访问权限,但可以查看他们有权访问的所有相关数据库记录。客户是我们销售计划的人,他们对管理员的访问权限有限,只能看到与他们相关的记录。用户是我们客户的客户......

在这一点上,django权限是不够的,因为我们的客户必须看到记录属于他的帐户,而标准管理员可以看到所有记录。这两个可以根据他们的权限到达应用程序。超级用户可以看到并做任何事情......

对于解决方案,我们创建了一个扩展Django用户的模型,而不是usnig django网站应用程序(我从未使用过,也没有太多信息),它有一个像角色这样的字段是用户角色是系统管理员,然后他可以看到所有内容(如果超级用户,否则他正常使用权限)...如果没有,他可以访问与他们的网站相关的记录(公司在您的情况下)。

因此,几乎每个数据库表都必须有一个外键来定义相关记录的所有者公司。

如果需要,您可以过滤属于特定公司的记录......

在我的模型中,我有继承用户模型的Kullanici

class Kullanici(User):
    rol = SmallIntegerField()# 1 if system admin, 2 if cusotmer etc...

然后,我写了几个方法来覆盖管理方法,like ;ModelAdmin.save and 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)

你给出了一个要隐藏的字段名称列表,如果用户不是系统管理员,它会隐藏它们...

Handycaps是,django管理员缓存可能会导致,这发生在我身上,在8个月内发生过一次或两次。其他重要的部分是,您不能限制管理过滤器,因此如果您有一个需要访问限制访问权限的过滤器,则无法过滤过滤器密钥。您可以使用所有选项显示它,也可以不使用它。

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

更新:是的,如果您查看 permission_required装饰器的源代码 from the latest trunk code...

,权限系统既简单又安全

逻辑简单,用户有相关权限,相关视图被删除。否则根本不执行相关的视图或代码。因此,权限为django admin提供了足够的安全性。 权限控制可以在视图级别和/或模板级别上使用。

必须注意的一点是手写的视图,其中不安全的代码可能会导致严重的问题,但这完全与您的编码有关,这就是您将在每种框架和编程语言中面临的安全风险。 ..

最后一个问题是django和admin视图页面的过滤机制。由于几乎所有管理过滤器都使用GET过滤数据,并将id传递给url以显示特定记录。 Seciruty part of django book显示了有关可能的安全问题以及django如何处理它们的基本信息......另一方面,22 December 2010 security update显示了一个如此重要的漏洞,需要有关模型结构的足够信息。

答案 1 :(得分:10)

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来编辑实际对象,请参阅this section of the source code引发change_view异常:

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,用户将被拒绝访问。

答案 2 :(得分:0)

如果管理员 - 使用提供的钩子定制,必要时 - 满足您的需求,那么当然没有理由不使用它。关键是你必须对它提供的内容和它没有提供的内容保持现实,并确保你不会开始需要只能在管理员之外的功能。我一直走在那条路上,并不漂亮。