Django用户层次结构

5
我要制作一个Web应用程序,类似于用户层级结构。我想这样做: 1. 超级用户创建具有某些权限的用户,这些用户也可以添加拥有它们自己权限的用户。这些用户也可以添加用户,以此类推。没有人应该能够编辑权限更高的用户。
问题在于,我希望将Django管理面板提供给所有这些用户使用。这种做法是否可行?我已经搜索了网络,并没有找到解决方案。谢谢建议。
3个回答

2
每个需要访问管理员的用户必须具有 is_staff=True 标志。允许未与您的组织相关联的用户访问管理员永远不是一个好主意。认真对待,不要这样做。如果这是您的计划,请另寻他路。
话虽如此,它仍然可以完成,但需要付出很多努力。首先,子类化默认的 UserCreationFormUserChangeForm(Auth 在其管理员中使用两个单独的表单)。覆盖每个表单的 __init__ 方法以从 kwargs 中提取 request(表单默认不会获取请求,但在这里是必要的,因此您需要进行一些变通处理)。然后,子类化默认的 UserAdmin,将 formadd_form 设置为新表单,并覆盖 get_form(以传递 request)和每个 has_foo_permission 方法以限制访问。还需要重写 queryset 方法,以便用户只能在管理员中看到他们可以修改的用户。
from django.contrib.auth.admin import UserAdmin
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from django.contrib.auth.models import Group, Permission

class CustomUserCreationForm(UserCreationForm):
    class Meta(UserCreationForm.Meta):
        pass

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)

        super(CustomUserCreationForm, self).__init__(*args, **kwargs)

        # Limit groups and permissions to those that belong to current user
        if self.request and not self.request.user.is_superuser:
            self.fields['groups'].queryset = self.request.user.groups.all()
            self.fields['user_permissions'].queryset = self.request.user.user_permissions.all()

 class CustomUserChangeForm(UserChangeForm):
    class Meta(UserChangeForm.Meta):
        pass

    def __init__(self, *args, **kwargs):
        self.request = kwargs.pop('request', None)

        super(CustomUserChangeForm, self).__init__(*args, **kwargs)

        # Limit groups and permissions to those that belong to current user
        if self.request and not self.request.user.is_superuser:
            self.fields['groups'].queryset = self.request.user.groups.all()
            self.fields['user_permissions'].queryset = self.request.user.user_permissions.all()

class CustomUserAdmin(UserAdmin):
    form = UserChangeForm
    add_form = UserCreationForm

    limited_fieldsets = ( # Copied from default `UserAdmin`, but removed `is_superuser`
        (None, {'fields': ('username', 'password')}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
        (_('Permissions'), {'fields': ('is_active', 'is_staff', 'user_permissions')}),
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
        (_('Groups'), {'fields': ('groups',)}),
    )

    def get_fieldsets(self, request, obj=None):
        if not obj:
            return self.add_fieldsets
        elif not request.user.is_superuser:
            return self.limited_fieldsets
        else:
            return super(CustomUserAdmin, self).get_fieldsets(request, obj)

    def get_form(self, request, obj=None, **kwargs):
        """Return a metaclass that will automatically pass `request` kwarg into the form"""
        ModelForm = super(LinkAdmin, self).get_form(request, obj, **kwargs)
        class ModelFormMetaClass(ModelForm):
            def __new__(cls, *args, **kwargs):
                kwargs['request'] = request
                return ModelForm(*args, **kwargs)
        return ModelFormMetaClass

    def has_add_permission(self, request):
        """
        If not superuser only allow add if the current user has at least some
        groups or permissions. (they'll have to be able to at least have something
        to assign the user they are creating).
        """
        if not request.user.is_superuser:
            if not request.user.groups.exists() or not request.user.user_permissions.exist():
                return False

        return True


    def has_change_permission(self, request, obj=None):
        """
        If not superuser, current user can only modify users who have a subset of the
        groups and permissions they have.
        """

        if obj and not request.user.is_superuser:
            # Check that all of the object's groups are in the current user's groups
            user_groups = list(request.user.groups.all())
            for group in obj.groups.all():
                try:
                    user_groups.index(group)
                except ValueError:
                    return False

            # Check that all of the object's permissions are in the current user's permissions
            user_permissions = list(request.user.user_permissions.all())
            for permission in obj.user_permissions.all():
                try:
                    user_permissions.index(permission)
                except ValueError:
                    return False

        return True

    def has_delete_permission(self, request, obj=None):
        """Same logic as `has_change_permission`"""
        return self.has_change_permission(request, obj)

    def queryset(self, request):
        qs = super(CustomUserAdmin, self).queryset(self, request)

        if request.user.is_superuser:
            return qs
        else:
            """
            This part is a little counter-intuitive. We're going to first get a
            list of all groups/permissions that don't belong to the user, and
            then use that to exclude users that do have those from the queryset.
            """

            user_group_pks = [g.pk for g request.user.groups.values('pk')]
            exclude_groups = Group.objects.exclude(pk__in=user_group_pks)

            user_permission_pks = [p.pk for p in request.user.user_permissions.values('pk')]
            exclude_permissions = Permission.objects.exclude(pk__in=user_permission_pks)

            return qs.exclude(groups__in=exclude_groups, user_permissions__in=exclude_permissions)

admin.site.unregister(User)
admin.site.register(User, CustomUserAdmin)

我可能误读了代码,但是你似乎没有防止用户设置超级用户标志。 - Alasdair
1
哈哈。是的,我也应该加上那个。一开始编写这段代码就非常费劲,我知道我会漏掉一些东西。无论是否应该实际使用这个功能都是有争议的,但它可以完成,所以我想尝试一下;)。 - Chris Pratt

2
如果您想控制所创建用户的权限,那么您需要为添加用户创建自己的视图。在Django管理站点上,任何能够创建用户的用户都可以创建超级用户。
从Django文档中关于创建用户的内容:
“如果您想让自己的用户账户能够使用Django管理站点创建用户,您需要给自己添加添加用户和更改用户的权限(即“添加用户”和“更改用户”权限)。如果您的账户只有添加用户的权限而没有更改用户的权限,那么您将无法添加用户。为什么呢?因为如果您有添加用户的权限,就可以创建超级用户,然后超级用户可以更改其他用户。因此,Django要求添加和更改权限作为一种轻微的安全措施。”

1

Django内置了一个用户层次结构维护系统 - Django-RBAC。

RBAC代表基于角色的访问控制。它是一种根据层次结构创建和管理权限的机制。您只需要稍微学习一下就可以了。


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