Django自定义用户模型密码未被哈希化。

24

我有自己的自定义用户模型,以及它自己的管理器。

模型:

class MyUser(AbstractBaseUser, PermissionsMixin):
    email = models.EmailField(max_length=255, unique=True)
    first_name = models.CharField(max_length=35)
    last_name = models.CharField(max_length=35)
    username = models.CharField(max_length=70, unique=True)
    date_of_birth = models.DateField()
    is_active = models.BooleanField(default=True)
    is_admin = models.BooleanField(default=False)

    @property
    def is_staff(self):
        return self.is_admin

    def get_full_name(self):
        return ('%s %s') % (self.first_name, self.last_name)

    def get_short_name(self):
        return self.username

    objects = MyUserManager()
    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['first_name', 'last_name', 'username', 'date_of_birth']

经理:

class MyUserManager(BaseUserManager):
    def create_user(self, email, first_name, last_name, username, date_of_birth, password=None, **kwargs):
        if not email:
            raise ValueError('User must have an email address')

        user = self.model(
            email=self.normalize_email(email),
            first_name=first_name,
            last_name=last_name,
            username=username,
            date_of_birth=date_of_birth,
            **kwargs
        )
        user.set_password(self.cleaned_data["password"])
        user.save(using=self._db)
        return user

    def create_superuser(self, email, first_name, last_name, username, date_of_birth, password, **kwargs):
        user = self.create_user(
            email,
            first_name=first_name,
            last_name=last_name,
            username=username,
            date_of_birth=date_of_birth,
            password=password,
            is_superuser=True,
            **kwargs
        )
        user.is_admin = True
        user.save(using=self._db)
        return user

创建新用户时没有任何错误,但尝试登录时无法登录。所以我检查了用户的密码确认,密码以纯文本strongpassword显示。当我更改管理表单以使用ReadOnlyPasswordHashField获取哈希密码时,我在密码字段内部获得了一个错误,即使我在create_user()函数中为管理员使用了set_password()

密码格式无效或未知的哈希算法

但是,如果我手动对该用户执行set_password('strongpassword'),则会对其进行哈希处理。请问您能否帮助我解决这个问题?谢谢。


我的猜测是,你的 self.create_superuser 没有调用你自定义的 self.create_user,而是调用了默认的。你能否设置一个断点并检查一下? - karthikr
@karthikr,抱歉我不知道如何设置断点。 - Benjamin Smith Max
尝试使用以下代码包装您的密码:from django.contrib.auth.hashers import make_password。然后只需使用 make_password(password) 即可。 - George Pligoropoulos
4个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
20

看起来您创建了一个用户,但是没有使用您的管理器的 create_user 方法进行创建,例如通过 Django 管理界面。

如果要创建自定义用户,需要定义一个自定义模型表单和模型管理员,以便正确处理密码。

否则,通过 Django 管理界面创建用户时,密码不会被哈希。

文档示例中,展示了如何创建模型表单和模型管理员,用于创建自定义用户。


在回答中提供一个工作示例会很有帮助,而不是指向第三方文档。例如,我正在尝试使用文档中的“完整示例”,但由于有许多动态部分,不清楚为什么它不起作用,哪个部分与实际解决问题相关。谢谢。 - Fed
1
@FedericoCapaldo 我不同意。如果你搜索一下,可能会找到一个包含完整示例的博客文章,但我认为这个回答不是最好放置它的地方。我更喜欢链接到官方文档。如果我看到有潜在的改进,我宁愿提交一个补丁来修改文档,而不是在这里重复它们。 - Alasdair

5

我知道现在已经太晚了,但是为了将来的参考,我还是要发布这篇文章。如果你正在通过调用序列化器的保存函数来创建新用户,则需要像下面所示覆盖序列化器的创建函数(这很明显,但我也被卡住了一会儿...)。

class SignUpView(views.APIView):
    authentication_classes = ()
    permission_classes = (permissions.AllowAny,)

    def post(self, request, format=None):
        serializer = UserSerializer(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=status.HTTP_201_CREATED)
class UserSerializer(serializers.ModelSerializer):

    password = serializers.CharField(
        min_length=6, write_only=True, required=True)

    class Meta:
        model = User
        fields = (
            'id', 'email', 'password', 'is_staff',
            'is_active', 'date_joined')

    def create(self, validated_data):
        return User.objects.create_user(**validated_data)

1
这看起来像是Django Rest Framework的代码?虽然它可能已经在DRF中解决了相关问题,但它并没有真正回答在这里提出的问题。 - melwil
这实际上解决了我在使用Django rest框架时遇到的问题,我忘记做这个了。干杯! - Onengiye Richard

2
晚了一些,但是无论如何,您需要使用明确的哈希算法来制作自定义用户模型表单。 否则,只需继承UserCreationForm创建表单即可,如下所示:
from .models import MyUser
from django.contrib.auth.forms import UserCreationForm    
class UserForm(UserCreationForm):

    class Meta:
        model = User
        fields = ['email']

0

在您的UserSerializer中添加此内容。 基本上,您必须重写create方法以对密码进行哈希。

def create(self,validated_data):
        user = User.objects.create(email = validated_data['email'])
        user.set_password(validated_data['password'])
        user.save()
        return user

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,