Поле пароля видно и не зашифровано на сайте администратора Django

Для использования email в качестве имени пользователя я переопределяю встроенную модель User следующим образом (вдохновлен исходным кодом Django)

models.py

class User(AbstractUser):
    username = None
    email = models.EmailField(unique=True)
    objects = UserManager()
    USERNAME_FIELD = "email"
    REQUIRED_FIELDS = []

    def __str__(self):
        return self.email

admin.py

@admin.register(User)
class UserAdmin(admin.ModelAdmin):
    fieldsets = (
        (None, {"fields": ("email", "password")}),
        (("Personal info"), {"fields": ("first_name", "last_name")}),
        (
            ("Permissions"),
            {
                "fields": (
                    "is_active",
                    "is_staff",
                    "is_superuser",
                    "groups",
                    "user_permissions",
                ),
            },
        ),
        (("Important dates"), {"fields": ("last_login", "date_joined")}),
    )
    add_fieldsets = (
        (
            None,
            {
                "classes": ("wide",),
                "fields": ("email", "password1", "password2"),
            },
        ),
    )
    list_display = ("email", "is_active", "is_staff", "is_superuser")
    list_filter = ("is_active", "is_staff", "is_superuser")
    search_fields = ("email",)
    ordering = ("email",)
    filter_horizontal = ("groups", "user_permissions",)

Но вот как это выглядит, когда я захожу на сайт администратора, чтобы изменить пользователя:

enter image description here

Пароль видим и не хэширован и нет ссылки на форму изменить пароль.

Сравнивая с тем, как это выглядит в проекте Django по умолчанию:

enter image description here

Пароль не виден и есть ссылка на форму смены пароля

Итак, очевидно, что я что-то упускаю, но не могу понять, что именно.

Вы создали пользователя на странице администратора или с помощью формы?

Смотрите, если вы создали пользователя со страницы администратора, пароль не будет хэшироваться... это может быть корнем вашей проблемы.

Скорее всего, это связано с наследованием. Точнее, измените класс так, чтобы он наследовался от UserAdmin.

from django.contrib.auth.admin import UserAdmin as DefaultUserAdmin

class UserAdmin(DefaultUserAdmin):

Если этого все еще недостаточно, тогда это должно быть проблемой в том, как сохраняется пользователь, и в этом случае я хотел бы увидеть код, присутствующий в классе UserManager(BaseUserManager); более точно, я посмотрю, использует ли ОП что-то вроде user.set_password(password) (если нет, то ОП должен).


В качестве примечания, я также использую AbstractUser, когда хочу удалить username.

Вы не можете увидеть пароль в хэшированном состоянии, потому что поле password является CharField, которое отображает его как обычное текстовое поле. В админке Django есть поле под названием ReadOnlyPasswordHashField в django.contrib.auth.forms, которое отображает поле пароля в хэшированном состоянии со ссылкой на изменение пароля.

В Django UserAdmin используются разные классы форм для создания и обновления пользователей.

    form = UserChangeForm
    add_form = UserCreationForm
    change_password_form = AdminPasswordChangeForm

Для редактирования данных пользователя UserAdmin используется form = UserChangeForm(исходный код), где поле пароля установлено как ReadOnlyPasswordHashField(исходный код).

class UserChangeForm(forms.ModelForm):
    password = ReadOnlyPasswordHashField(
        label=_("Password"),
        help_text=_(
            "Raw passwords are not stored, so there is no way to see this "
            "user’s password, but you can change the password using "
            '<a href="{}">this form</a>.'
        ),
    )

Итак, простое наследование от UserAdmin от django.contrib.auth.admin заставит пароль быть в хэшированном состоянии со всеми остальными необходимыми элементами, как это показано на стандартном сайте администратора для пользователей.

ИЛИ

вы можете просто импортировать UserChangeForm из django.contrib.auth.forms и установить form = UserChangeForm в пользовательском UserAdmin

from django.contrib.auth.forms import UserChangeForm

# code

@admin.register(User)
class UserAdmin(admin.ModelAdmin):
    # code
    form = UserChangeForm
    change_password_form = AdminPasswordChangeForm
    # code

Документация Django ясно объясняет, как это сделать в Настройка аутентификации в Django

from django import forms
from django.contrib import admin
from django.contrib.auth.models import Group
from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
from django.contrib.auth.forms import ReadOnlyPasswordHashField
from django.core.exceptions import ValidationError

from customauth.models import MyUser


class UserCreationForm(forms.ModelForm):
    """A form for creating new users. Includes all the required
    fields, plus a repeated password."""
    password1 = forms.CharField(label='Password', widget=forms.PasswordInput)
    password2 = forms.CharField(label='Password confirmation', widget=forms.PasswordInput)

    class Meta:
        model = MyUser
        fields = ('email', 'date_of_birth')

    def clean_password2(self):
        # Check that the two password entries match
        password1 = self.cleaned_data.get("password1")
        password2 = self.cleaned_data.get("password2")
        if password1 and password2 and password1 != password2:
            raise ValidationError("Passwords don't match")
        return password2

    def save(self, commit=True):
        # Save the provided password in hashed format
        user = super().save(commit=False)
        user.set_password(self.cleaned_data["password1"])
        if commit:
            user.save()
        return user


class UserChangeForm(forms.ModelForm):
    """A form for updating users. Includes all the fields on
    the user, but replaces the password field with admin's
    disabled password hash display field.
    """
    password = ReadOnlyPasswordHashField()

    class Meta:
        model = MyUser
        fields = ('email', 'password', 'date_of_birth', 'is_active', 'is_admin')


class UserAdmin(BaseUserAdmin):
    # The forms to add and change user instances
    form = UserChangeForm
    add_form = UserCreationForm

    # The fields to be used in displaying the User model.
    # These override the definitions on the base UserAdmin
    # that reference specific fields on auth.User.
    list_display = ('email', 'date_of_birth', 'is_admin')
    list_filter = ('is_admin',)
    fieldsets = (
        (None, {'fields': ('email', 'password')}),
        ('Personal info', {'fields': ('date_of_birth',)}),
        ('Permissions', {'fields': ('is_admin',)}),
    )
    # add_fieldsets is not a standard ModelAdmin attribute. UserAdmin
    # overrides get_fieldsets to use this attribute when creating a user.
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            'fields': ('email', 'date_of_birth', 'password1', 'password2'),
        }),
    )
    search_fields = ('email',)
    ordering = ('email',)
    filter_horizontal = ()


# Now register the new UserAdmin...
admin.site.register(MyUser, UserAdmin)

Один из способов - определить пользовательский набор полей для UserAdmin в файле admin.py.

fieldsets = (
    (None, {"fields": ("username")}),
    (_("Personal info"), {"fields": ("first_name", "last_name", "email")}),
    (
        _("Permissions"),
        {
            "fields": (
                "is_active",
                "is_staff",
                "is_superuser",
                "groups",
                "user_permissions",
            ),
        },
    ),
    (_("Important dates"), {"fields": ("last_login", "date_joined")}),
)
Вернуться на верх