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

8

我目前正在实现一个Django应用程序的认证,我正在编写。按照Thinkster Django课程的代码,我实现了整个注册流程,但我无法登录,因为在注册用户时密码没有被哈希。

这是我的自定义用户模型和create_user函数。

class UserManager(BaseUserManager)
    def create_user(self, username, email, password=None):

        if username is None:
            raise TypeError('Users must have a username.')

        if email is None:
            raise TypeError('Users must have an email address.')

        user = self.model(username=username, email=self.normalize_email(email))
        user.set_password(password)
        user.save()

        return user

    def create_superuse(self, username, email, password):
        if password is None:
            raise TypeError('Superusers must have a password.')

        user = self.create_user(username, email, password)
        user.is_superuser = True
        user.is_staff = True
        user.save()

        return user

class User(AbstractBaseUser, PermissionsMixin):
    username = models.CharField(db_index=True, max_length=255, unique=True)
    email = models.EmailField(db_index=True, unique=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    objects = UserManager()

如您所见,我明确调用了“set_password”函数,但我无法找出为什么它不能得到正确执行?
我的序列化器(Serializer)如下所示,其中我创建了用户:
class RegistrationSerializer(serializers.ModelSerializer):

    password = serializers.CharField(
        max_length=128,
        min_length=8,
        write_only=True
    )

token = serializers.CharField(max_length=255, read_only=True)

class Meta:
    model = User
    fields = ['email', 'username', 'password', 'token']

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

请注意,与return User.objects.create_user(**validated_data)不同的是,我还尝试使用return get_user_model().objects.create_user(**validated_data),因为这是另一个问题中的建议,但那也没有起作用。
我也发布了我的视图,以防有什么问题,但我真的不认为那是问题所在。
class RegistrationAPIView(APIView):
    permission_classes = (AllowAny,)
    renderer_classes = (UserJSONRenderer,)
    serializer_class = RegistrationSerializer

    def post(self, request):
        user = request.data.get('user', {})

        serializer = self.serializer_class(data=user)
        serializer.is_valid(raise_exception=True)
        serializer.save()

        return Response(serializer.data, status=status.HTTP_201_CREATED)
旁注: 如果相关的话,我使用Postman发送请求并且所有返回的响应看起来都是正确的。但是当我浏览我的SQLite时,我发现密码没有被散列。这也导致用户无法登录,因为在登录过程中,密码会被散列然后与数据库中的密码进行比较。 旁注2: 当我通过命令行使用python manage.py createsuperuser注册用户时,它会得到一个散列密码,一切都按照我的正常预期运行。

你是否已经添加了 PASSWORD_HASHERSmake_password 方法??https://docs.djangoproject.com/en/1.10/ref/settings/#std:setting-PASSWORD_HASHERShttps://docs.djangoproject.com/en/1.8/topics/auth/passwords/#django.contrib.auth.hashers.make_password - Surajano
原来我没有添加。我现在添加了 PASSWORD_HASHERS 列表,但是我应该在哪里编写我的 make_password 函数呢? - Lysandros Nikolaou
抱歉问个傻问题,create_user 函数是否在 UserManager 类中声明的?:) - neverwalkaloner
是的,如果我没有表达清楚,对不起。 - Lysandros Nikolaou
3个回答

4
我在上述评论中所说的make_password是指在create_user方法中添加以下内容:
from django.contrib.auth.hashers import make_password


def create_user(self, username, email, password=None):

    if username is None:
        raise TypeError('Users must have a username.')

    if email is None:
        raise TypeError('Users must have an email address.')

    user = User.objects.create(
       email=email,
       username=username,
       password = make_password(password))

    return user

我认为set_password会对提供的密码进行哈希处理,正如这里所记录的那样,因此我不认为这是问题所在。 - Lysandros Nikolaou
1
这对我们起作用了,我们正在使用django版本1.11.12。以前我们不需要使用make_password就可以工作,但最近可能发生了变化。 - George Pligoropoulos

3
您需要在序列化器中使用set_password方法,如下所示:

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

我认为这不对。我在我的create_user函数中正是这样做的。那就是它的目的。 - Lysandros Nikolaou

0

我认为Surajano正在做正确的事情。我不知道这是否能解决你的问题,但我曾经遇到过创建超级用户未散列密码的同样问题。

我的解决方法:

def create_superuser(self, email, first_name, last_name, password):
    user = self.create_user(
        email,
        first_name,
        last_name,
        password=password,
    )

你必须明确设置password=password。

此外,我在你的def create_superuser中看到了一个拼写错误(你将其作为def create_superuse),这可能会在以后给你带来一些麻烦。

无论如何,我在这里发布了一个问题和解决方案,你可以在这里查看:

UserCreateForm绕过UserManager,通过UserCreateForm创建的普通用户可以进行身份验证,但在shell中创建的超级用户不能进行身份验证?

再次声明,我不知道这是否对你有所帮助,但希望它至少能给你追踪解决方案的思路。我的示例不使用基于令牌的身份验证 - 因此没有序列化器 - 但我认为这并不重要,因为它们很可能是无关的。


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