كيف يمكنني منع تصعيد الإذن في مسؤول Django عند منح إذن "تغيير المستخدم"؟

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

سؤال

لدي موقع Django مع قاعدة عملاء كبيرة. أود أن أعطي قسم خدمة العملاء لدينا القدرة على تغيير حسابات المستخدم العادية ، والقيام بأشياء مثل تغيير كلمات المرور وعناوين البريد الإلكتروني ، وما إلى ذلك ، إذا منحت شخصًا ما مدمجًا في شخص ما auth | user | Can change user إذن ، يكتسبون القدرة على تعيين is_superuser العلم على أي حساب ، بما في ذلك خاصة بهم. (!!!)

ما هي أفضل طريقة لإزالة هذا الخيار للموظفين غير الخاطفين؟ أنا متأكد من أنه ينطوي على التصنيف الفرعي django.contrib.auth.forms.UserChangeForm وربطه في بلدي بالفعل UserAdmin كائن ... بطريقة ما. لكن لا يمكنني العثور على أي وثائق حول كيفية القيام بذلك ، ولم أفهم بعد الأجزاء الداخلية جيدًا بما فيه الكفاية.

هل كانت مفيدة؟

المحلول

يكتسبون القدرة على تعيين علامة is_superuser على أي حساب ، بما في ذلك خاصة بهم. (!!!)

ليس هذا فحسب ، بل يكتسبون أيضًا القدرة على إعطاء أنفسهم أي أذونات واحدة تلو الأخرى ، نفس التأثير ...

أنا متأكد من أنه يتضمن تصنيف django.contrib.auth.forms.userChangeform

حسنا ، ليس بالضرورة. يتم إنشاء النموذج الذي تراه في صفحة تغيير مسؤول Django ديناميكيًا بواسطة تطبيق المسؤول ، واستنادًا إلى UserChangeForm, ، لكن هذه الفئة بالكاد تضيف التحقق من صحة regex إلى username مجال.

وربطه في كائن useradmin الخاص بي بالفعل ...

عادة UserAdmin هو الطريق للذهاب هنا. في الأساس ، تريد تغيير fieldsets خاصية لشيء من هذا القبيل:

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',)}),
    )

لكن المشكلة هنا هي أن هذا التقييد سوف ينطبق على جميع المستخدمين. إذا لم يكن هذا ما تريد ، فيمكنك على سبيل المثال تجاوز change_view للتصرف بشكل مختلف اعتمادًا على إذن المستخدمين. قصاصة الكود:

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)

نصائح أخرى

الجزء أدناه من الإجابة المقبولة لديه حالة سباق حيث إذا حاول اثنان من الموظفين الوصول إلى نموذج المسؤول في نفس الوقت ، فقد يحصل أحدهما على نموذج Superuser.

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

لتجنب حالة السباق هذه (وفي رأيي ، تحسين الجودة الإجمالية للحل) ، يمكننا تجاوز get_fieldsets() و get_readonly_fields() الطرق مباشرة:

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)

شكرا جزيلا ل Clément. ما توصلت إليه عند فعل الشيء نفسه لموقعي هو أنني بحاجة بالإضافة إلى ذلك لجعل جميع الحقول قراءة للمستخدمين غير نفسك. لذا ، فإن الإجابة على Clément ، أقوم بإضافة حقول ReadOnly وحقل كلمة المرور المختبئين عند مشاهدة غير الذات

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)

الرمز الكامل لـ Django 1.1 (يقتصر على معلومات المستخدم الأساسية للموظفين (وليس الخبراء))

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)

تم وضع هذا النهج من عدة نصائح مفيدة على الويب. في هذه الحالة ، نقوم بتعديل userAdmin ، بحيث بالنسبة للموظفين غير الخاطفين مع الإذن بإضافة/تغيير المستخدم ، فإن الأذونات والمجموعات الوحيدة التي يمكنهم منح مستخدم آخر هي الموظفين بالفعل.

(لـ 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)

يجب أن يتم ذلك بالمثل لـ GroupAdmin إذا تم منح المستخدم إذنًا لتغيير المجموعات.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top