Wie verhindern Sie die Eskalation in Django Admin, wenn ich die Berechtigung „Benutzeränderung“ erteilt?

StackOverflow https://stackoverflow.com/questions/2297377

Frage

Ich habe eine Django -Website mit einem großen Kundenstamm. Ich möchte unserer Kundendienstabteilung die Möglichkeit geben, normale Benutzerkonten zu ändern, Dinge wie das Ändern von Kennwörtern, E-Mail-Adressen usw. durchzuführen auth | user | Can change user Erlaubnis erlangen die Fähigkeit, die festzulegen is_superuser Fahnen Sie auf jedem Konto, einschließlich ihrer eigenen. (!!!)

Was ist der beste Weg, um diese Option für Nicht-Superuser-Mitarbeiter zu entfernen? Ich bin sicher, es geht um Unterklassigen django.contrib.auth.forms.UserChangeForm und es in meinen bereits kundenspezifischen Anschlüsse einbeziehen UserAdmin Objekt ... irgendwie. Aber ich kann keine Dokumentation dazu finden, wie es geht, und ich verstehe die Interna noch nicht gut genug.

War es hilfreich?

Lösung

Sie erlangen die Möglichkeit, das IS_Superuser -Flag auf jedem Konto, einschließlich ihrer eigenen, festzulegen. (!!!)

Nicht nur das, sie erlangen auch die Fähigkeit, sich einzeln, gleiche Wirkung zu geben ...

Ich bin mir sicher

Nun, nicht unbedingt. Das Formular, das Sie auf der Änderungsseite des Administrators von Django sehen UserChangeForm, aber diese Klasse fügt der Regex -Validierung kaum zu dem hinzu username aufstellen.

und einbinden es in mein bereits kundenspezifisches UserAdmin-Objekt ...

Ein Brauch UserAdmin ist der richtige Weg hierher. Grundsätzlich möchten Sie die ändern fieldsets Eigenschaft zu so etwas:

class MyUserAdmin(UserAdmin):
    fieldsets = (
        (None, {'fields': ('username', 'password')}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
        # Removing the permission part
        # (_('Permissions'), {'fields': ('is_staff', 'is_active', 'is_superuser', 'user_permissions')}),
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
        # Keeping the group parts? Ok, but they shouldn't be able to define
        # their own groups, up to you...
        (_('Groups'), {'fields': ('groups',)}),
    )

Das Problem hierfür ist jedoch, dass diese Einschränkung für alle Benutzer gilt. Wenn dies nicht das ist, was Sie wollen, können Sie beispielsweise überschreiben change_view sich je nach Erlaubnis der Benutzer anders verhalten. Code-Auszug :

class MyUserAdmin(UserAdmin):
    staff_fieldsets = (
        (None, {'fields': ('username', 'password')}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
        # No permissions
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
        (_('Groups'), {'fields': ('groups',)}),
    )

    def change_view(self, request, *args, **kwargs):
        # for non-superuser
        if not request.user.is_superuser:
            try:
                self.fieldsets = self.staff_fieldsets
                response = super(MyUserAdmin, self).change_view(request, *args, **kwargs)
            finally:
                # Reset fieldsets to its original value
                self.fieldsets = UserAdmin.fieldsets
            return response
        else:
            return super(MyUserAdmin, self).change_view(request, *args, **kwargs)

Andere Tipps

Der folgende Teil der akzeptierten Antwort hat eine Rennbedingung, bei der zwei Mitarbeiter, die versuchen, gleichzeitig auf das Admin -Formular zuzugreifen, eine von ihnen möglicherweise das Superuser -Formular erhalten.

try:
    self.readonly_fields = self.staff_self_readonly_fields
    response = super(MyUserAdmin, self).change_view(request, object_id, form_url, extra_context, *args, **kwargs)
finally:
    # Reset fieldsets to its original value
    self.fieldsets = UserAdmin.fieldsets

Um diese Rennbedingung zu vermeiden (und meiner Meinung nach die Gesamtqualität der Lösung zu verbessern) können wir das überschreiben get_fieldsets() und get_readonly_fields() Methoden direkt:

class UserAdmin(BaseUserAdmin):
    staff_fieldsets = (
        (None, {'fields': ('username')}),
        ('Personal info', {'fields': ('first_name', 'last_name', 'email')}),
        # No permissions
        ('Important dates', {'fields': ('last_login', 'date_joined')}),
    )
    staff_readonly_fields = ('username', 'first_name', 'last_name', 'email', 'last_login', 'date_joined')

    def get_fieldsets(self, request, obj=None):
        if not request.user.is_superuser:
            return self.staff_fieldsets
        else:
            return super(UserAdmin, self).get_fieldsets(request, obj)

    def get_readonly_fields(self, request, obj=None):
        if not request.user.is_superuser:
            return self.staff_readonly_fields
        else:
            return super(UserAdmin, self).get_readonly_fields(request, obj)

Toll Dank an Clément. Was ich bei der Tat dasselbe für meine Website entwickelt habe, ist, dass ich zusätzlich alle Felder für Benutzer als sich selbst readonly machen musste. Also stütze ich mich auf Cléments Antwort. Ich füge readonly Felder und Kennwort -Feld versteckt, wenn ich mich nicht selbst anzeigen kann

class MyUserAdmin(UserAdmin):
    model = User
    staff_self_fieldsets = (
        (None, {'fields': ('username', 'password')}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
        # No permissions
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
    )

    staff_other_fieldsets = (
        (None, {'fields': ('username', )}),
        (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
        # No permissions
        (_('Important dates'), {'fields': ('last_login', 'date_joined')}),
    )

    staff_self_readonly_fields = ('last_login', 'date_joined')

    def change_view(self, request, object_id, form_url='', extra_context=None, *args, **kwargs):
        # for non-superuser
        if not request.user.is_superuser:
            try:
                if int(object_id) != request.user.id:
                    self.readonly_fields = User._meta.get_all_field_names()
                    self.fieldsets = self.staff_other_fieldsets
                else:
                    self.readonly_fields = self.staff_self_readonly_fields
                    self.fieldsets = self.staff_self_fieldsets

                response = super(MyUserAdmin, self).change_view(request, object_id, form_url, extra_context, *args, **kwargs)
            except:
                logger.error('Admin change view error. Returned all readonly fields')

                self.fieldsets = self.staff_other_fieldsets
                self.readonly_fields = ('first_name', 'last_name', 'email', 'username', 'password', 'last_login', 'date_joined')
                response = super(MyUserAdmin, self).change_view(request, object_id, form_url, extra_context, *args, **kwargs)
            finally:
                # Reset fieldsets to its original value
                self.fieldsets = UserAdmin.fieldsets
                self.readonly_fields = UserAdmin.readonly_fields
            return response
        else:
            return super(MyUserAdmin, self).change_view(request, object_id, form_url, extra_context, *args, **kwargs)

Voller Code für Django 1.1 (begrenzt auf grundlegende Benutzerinformationen für Mitarbeiter (nicht Superuser))

from django.contrib.auth.models import User
from django.utils.translation import ugettext_lazy as _


class MyUserAdmin(UserAdmin):
   my_fieldsets = (
       (None, {'fields': ('username', 'password')}),
       (_('Personal info'), {'fields': ('first_name', 'last_name', 'email')}),
   )

   def change_view(self, request, object_id, extra_context=None):
       # for non-superuser
       print 'test'
       if not request.user.is_superuser:
           self.fieldsets = self.my_fieldsets
           response = UserAdmin.change_view(self, request, object_id,
extra_context=None)
           return response
       else:
           return UserAdmin.change_view(self, request, object_id,
extra_context=None)


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

Dieser Ansatz wurde aus mehreren hilfreichen Tipps im Internet zusammengestellt. In diesem Fall ändern wir UserAdmin, so dass für Nicht-Superuser-Mitarbeiter mit Benutzerzusatz/Änderungsberechtigung die einzigen Berechtigungen und Gruppen, die sie einem anderen Benutzer gewähren können, diejenigen, die der Mitarbeiter bereits hat, gewähren können.

(für Django 1.11)

from django.contrib.auth.admin import UserAdmin, User
from django.contrib import admin

class RestrictedUserAdmin(UserAdmin):
    model = User

    def formfield_for_dbfield(self, db_field, **kwargs):
        field = super(RestrictedUserAdmin, self).formfield_for_dbfield(db_field, **kwargs)
        user = kwargs['request'].user
        if not user.is_superuser:
            if db_field.name == 'groups':
                field.queryset = field.queryset.filter(id__in=[i.id for i in user.groups.all()])
            if db_field.name == 'user_permissions':
                field.queryset = field.queryset.filter(id__in=[i.id for i in user.user_permissions.all()])
            if db_field.name == 'is_superuser':
                field.widget.attrs['disabled'] = True
        return field

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

Dies sollte ebenfalls für GroupAdmin erfolgen, wenn einem Benutzer die Erlaubnis zur Änderung der Gruppen erhält.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top