Поле пароля видно и не зашифровано на сайте администратора 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",)
Но вот как это выглядит, когда я захожу на сайт администратора, чтобы изменить пользователя:
Пароль видим и не хэширован и нет ссылки на форму изменить пароль.
Сравнивая с тем, как это выглядит в проекте Django по умолчанию:
Пароль не виден и есть ссылка на форму смены пароля
Итак, очевидно, что я что-то упускаю, но не могу понять, что именно.
Вы создали пользователя на странице администратора или с помощью формы?
Смотрите, если вы создали пользователя со страницы администратора, пароль не будет хэшироваться... это может быть корнем вашей проблемы.
Скорее всего, это связано с наследованием. Точнее, измените класс так, чтобы он наследовался от 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")}),
)