一尘不染

Django Admin-特定用户(admin)内容

django

我开始组织一个新项目,假设我将拥有一些模型,例如产品和目录。

我将允许我的客户(不是访问者,仅特定客户)登录Django Admin网站以创建,编辑和删除自己的目录。

假设我创建了一个名为“商店”的模型,创建了每个商店(名称,地址,徽标,联系信息等),并创建了绑定到该商店的管理员用户。

现在,我希望这个新管理员(不是站点管理员,而是商店管理员-可能是用户组)仅查看和编辑与他的商店链接的目录。

那可能吗?

我应该在Django Admin中执行此操作还是应该创建一个新的“ shop admin”应用程序?


阅读 518

收藏
2020-04-03

共1个答案

一尘不染

首先,警告:Django admin的设计理念是,有权访问admin(is_staff==True)的任何用户都是受信任的用户,例如员工,因此,“ staff”名称甚至可以访问admin。尽管你可以自定义管理员以限制区域,但允许组织内任何人访问你的管理员都是有风险的,并且Django在那时不保证任何安全性。

现在,如果你仍要继续操作,则可以通过简单地不将这些特权分配给用户来立即限制除了商店之外的大多数其他东西。你必须授予所有商店所有者权限,以编辑他们需要访问的任何商店模型,但其他所有内容都应保留在其权限列表之外。

然后,对于每个仅需限制所有者注意的模型,你将需要添加一个字段来存储“所有者”,或者用户允许对其进行访问。你可以使用上的save_model方法执行此操作,该方法ModelAdmin可以访问请求对象:

class MyModelAdmin(admin.ModelAdmin):
    def save_model(self, request, obj, form, change):
        obj.user = request.user
        super(MyModelAdmin, self).save_model(request, obj, form, change)

然后,你还需要将ModelAdmin的queryset限制为仅由当前用户拥有的那些项:

class MyModelAdmin(admin.ModelAdmin):
    def get_queryset(self, request):
        qs = super(MyModelAdmin, self).get_queryset(request)
        if request.user.is_superuser:
            return qs
        return qs.filter(owner=request.user)

但是,这只会限制列出的内容,用户仍然可以使用URL来访问他们无权访问的其他对象,因此,如果用户不是,则需要覆盖每个ModelAdmin的易受攻击的视图以进行重定向。主人:

from django.http import HttpResponseRedirect
from django.core.urlresolvers import reverse

class MyModelAdmin(admin.ModelAdmin):
    def change_view(self, request, object_id, form_url='', extra_context=None):
        if not self.queryset(request).filter(id=object_id).exists():
            return HttpResponseRedirect(reverse('admin:myapp_mymodel_changelist'))

        return super(MyModelAdmin, self).change_view(request, object_id, form_url, extra_context)

    def delete_view(self, request, object_id, extra_context=None):
        if not self.queryset(request).filter(id=object_id).exists():
            return HttpResponseRedirect(reverse('admin:myapp_mymodel_changelist'))

        return super(MyModelAdmin, self).delete_view(request, object_id, extra_context)

    def history_view(self, request, object_id, extra_context=None):
        if not self.queryset(request).filter(id=object_id).exists():
            return HttpResponseRedirect(reverse('admin:myapp_mymodel_changelist'))

        return super(MyModelAdmin, self).history_view(request, object_id, extra_context)

由于的查询集ModelAdmin已经受到用户的限制,因此你只能self.queryset()在更改,删除和历史视图中使用。这样可以很好地抽象出模型类名,从而减少代码的脆弱性。我还更改为使用filterexists而不是try...except使用get。这样更简化了,实际上也导致了更简单的查询。

2020-04-03