10

我正在使用django-guardian来管理每个对象的权限。

对于给定的用户,我授予对一个对象的所有权限:

joe = User.objects.get(username="joe")

mytask = Task.objects.get(pk=1)

assign('add_task', joe, mytask)
assign('change_task', joe, mytask)
assign('delete_task', joe, mytask)

正如预期的那样,我得到:

In [57]: joe.has_perm("add_task", mytask)
Out[57]: True

In [58]: joe.has_perm("change_task", mytask)
Out[58]: True

In [59]: joe.has_perm("delete_task", mytask)
Out[59]: True

在 admin.py 我也让 TaskAdmin 继承自GuardedModelAdmin而不是admin.ModelAdmin

现在,当我使用 joe 连接到我的网站时,在管理员上我得到:

You don't have permission to edit anything 

我不应该能够编辑对象 mytask 吗?

我是否必须使用内置的基于模型的权限系统设置一些权限?

我错过了什么吗?

编辑

我试图添加选项user_can_access_owned_objects_only,它应该可以解决我的问题,但我仍然在我的管理员中看不到任何东西......

class TaskAdmin(GuardedModelAdmin):

    user_can_access_owned_objects_only = True

    pass

admin.site.register(Task, TaskAdmin)

谢谢

4

2 回答 2

4

为了只看到当前用户拥有的实例,我给了他所有权限

add_task=Permission.objects.get(codename="add_task")
change_task=Permission.objects.get(codename="change_task")
delete_task=Permission.objects.get(codename="delete_task")

joe.user_permissions.add(add_task)
joe.user_permissions.add(change_task)
joe.user_permissions.add(delete_task)

然后我使用 Guardian.shortcuts.assign 在几个实例上设置权限,并在管理员中过滤查询集:

class TaskAdmin(admin.ModelAdmin):

    def queryset(self, request):
            if request.user.is_superuser:
                return super(TaskAdmin, self).queryset(request)
            return get_objects_for_user(user=request.user, perms=['add_task', 'change_task', 'delete_task'], klass=Task)

它远非完美,但我找不到任何其他解决方案。

于 2012-06-07T16:41:55.910 回答
4

Django Admin,特别是它处理 w/change权限,有点粗粒度。内部方法ModelAdmin.has_change_permission()涵盖了view实际缺乏的权限检查。

其次,GuardedModelAdmin带来了所有权检查(通过user_can_access_owned_objects_only)和用于管理行级权限的表单。它不向 Django Admin 提供任何其他行级访问策略。

对于 Django Admin 中典型的行级权限场景,我想建议代码,这里我引入了一个可选的“查看”权限:

class ExtendedGuardedModelAdmin(GuardedModelAdmin):
    def queryset(self, request):
        qs = super(ExtendedGuardedModelAdmin, self).queryset(request)
        # Check global permission
        if super(ExtendedGuardedModelAdmin, self).has_change_permission(request) \
            or (not self.list_editable and self.has_view_permission(request)):
                return qs
        # No global, filter by row-level permissions. also use view permission if the changelist is not editable
        if self.list_editable:
            return get_objects_for_user(request.user, [self.opts.get_change_permission()], qs)
        else:
            return get_objects_for_user(request.user, [self.opts.get_change_permission(), self.get_view_permission(
)], qs, any_perm=True)

    def has_change_permission(self, request, obj=None):
        if super(ExtendedGuardedModelAdmin, self).has_change_permission(request, obj):
            return True
        if obj is None:
            # Here check global 'view' permission or if there is any changeable items
            return self.has_view_permission(request) or self.queryset(request).exists()
        else:
            # Row-level checking
            return request.user.has_perm(self.opts.get_change_permission(), obj)

    def get_view_permission(self):
        return 'view_%s' % self.opts.object_name.lower()

    def has_view_permission(self, request, obj=None):
        return request.user.has_perm(self.opts.app_label + '.' + self.get_view_permission(), obj)

    def has_delete_permission(self, request, obj=None):
        return super(ExtendedGuardedModelAdmin, self).has_delete_permission(request, obj) \
                or (obj is not None and request.user.has_perm(self.opts.get_delete_permission(), obj))

这样,您可以实现更灵活的权限检查,用户权限现在是全局的,用户对象权限是基于行级的:

  • joe.user_permissions.add(add_task)
    joe 可以添加新任务(没有行级“添加”权限)
  • joe.user_permissions.add(change_task)
    乔可以改变所有的任务
  • joe.user_permissions.add(delete_task)
    joe 可以删除所有任务
  • assign(Task._meta.get_change_permission(), joe, obj)
    joe 可以更改 Task obj,查看包含 obj 的更改列表以及其他可更改的任务。
  • assign(Task._meta.get_delete_permission(), joe, obj)
    joe 可以删除任务 obj
  • assign('view_task', joe, obj)
    [可选] joe 可以查看任务 obj(您可能希望在自定义管理视图页面检查此权限)
  • joe.user_permissions.add(Permission.objects.get(codename='view_task', ...))
    [可选] joe 可以查看更改列表中的所有任务,只要更改列表不可内联编辑。如果 joe 可以在没有更改权限的情况下从 raw_id_fields 中获取项目,这将很有用。
  • ...

如果它对您没用,您可以安全地忽略“查看”权限。

目前,django.contrib.admin.util.get_deleted_objects在检查权限时不尊重 obj,如果您需要在删除时检查行级权限,请将行get_deleted_objects修改if not user.has_perm(p):if not user.has_perm(p, obj):. 相关票是13539 & 16862

于 2012-07-11T13:43:31.440 回答