Wie verhindern Sie die Eskalation in Django Admin, wenn ich die Berechtigung „Benutzeränderung“ erteilt?
-
21-09-2019 - |
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.
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.