Пользовательская иерархия Django - PullRequest
4 голосов
/ 11 ноября 2011

Я должен сделать веб-приложение, которое будет реализовывать что-то вроде пользовательской иерархии. Я хотел бы сделать это так: 1. Суперпользователь создает пользователей (с некоторыми разрешениями), которые также могут добавлять пользователей (только с разрешениями, которыми они владеют). Эти пользователи также могут добавлять пользователей и так далее. Никто не должен иметь возможность редактировать пользователей, у которых есть больше прав.

Дело в том, что я хочу сделать Django Admin Panel доступной для всех этих пользователей. Можно ли вообще сделать такую ​​вещь? Я искал в Интернете и не нашел решения. Спасибо за совет.

Ответы [ 3 ]

2 голосов
/ 11 ноября 2011

Каждый пользователь, которому понадобится доступ к администратору, должен иметь флаг is_staff=True. никогда - хорошая идея разрешить пользователям, не связанным с вашей организацией, доступ к администратору. Серьезно, просто не делай этого. Если это твой план, найди другой.

Тем не менее, это может быть сделано, но это не для слабонервных. Там много вовлечено. Первый подкласс по умолчанию UserCreationForm и UserChangeForm (Auth использует две отдельные формы для своего администратора). Переопределите метод __init__ каждого для извлечения request из kwargs (формы не получают запрос по умолчанию, но это необходимо здесь, поэтому вы должны сделать небольшой обходной путь). Затем подкласс по умолчанию UserAdmin, установите form и add_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)
2 голосов
/ 11 ноября 2011

Вам нужно будет создать свои собственные представления для добавления пользователей, если вы хотите контролировать разрешения созданных пользователей. На сайте администратора Django любой пользователь, который может создавать пользователей, может создавать суперпользователей.

Из документов Django на создание пользователей :

Если вы хотите, чтобы ваша собственная учетная запись могла создавать пользователей с помощью сайта администрирования Django, вам нужно дать себе разрешение на добавление пользователей и изменение пользователей (т. Е. Разрешения «Добавить пользователя» и «Изменить пользователя»). ). Если у вашей учетной записи есть разрешение на добавление пользователей, но не на их изменение, вы не сможете добавлять пользователей. Зачем? Потому что, если у вас есть разрешение на добавление пользователей, вы можете создавать суперпользователей, которые могут, в свою очередь, изменять других пользователей. Так что Django требует добавления и изменения разрешений в качестве небольшой меры безопасности.

1 голос
/ 11 ноября 2011

Django содержит встроенную систему поддержки Иерархии пользователей - Django-RBAC.

RBAC означает Контроль доступа на основе ролей . Это механизм для создания и управления разрешениями на основе иерархии. Вам просто нужно немного изучить это.

...