【问题标题】:Django set_password() method in UserManager is saving plain textUserManager 中的 Django set_password() 方法正在保存纯文本
【发布时间】:2020-03-09 07:25:59
【问题描述】:

我正在尝试为注册创建一个端点。 当我创建一个新用户时,一个纯文本将保存在密码字段中。但是,当我通过管理员添加用户时,它会被散列。我不确定我在这里缺少什么。

模型.py

class UserManager(BaseUserManager):
def _create_user(self, email, password=None, **extra_fields):
    if not email:
        raise ValueError('The given email must be set')

    user = self.model(
        email=self.normalize_email(email),
        **extra_fields,
    )
    user.set_password(password)
    user.save(using=self._db)
    return user

def create_user(self, email, password=None, **extra_fields):
    extra_fields.setdefault('is_superuser', False)
    return self._create_user(email, password, **extra_fields)

def create_superuser(self, email, password, **extra_fields):
    extra_fields.setdefault('is_staff', True)
    extra_fields.setdefault('is_admin', True)
    extra_fields.setdefault('is_superuser', True)

    if extra_fields.get('is_superuser') is not True:
        raise ValueError('Superuser must have is_superuser=True.')

    return self._create_user(email, password, **extra_fields)

序列化器.py

from rest_framework import serializers
from django.contrib.auth import authenticate
from .models import User
class RegisterSerializer(serializers.ModelSerializer):
class Meta:
    model = User
    fields = ('email', 'password')
    extra_kwargs = {'password': {'write_only': True}}

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

view.py

class RegisterAPI(generics.GenericAPIView):
serializer_class = RegisterSerializer

def post(self, request, *args, **kwargs):
    serializer = self.get_serializer(data=request.data)
    serializer.is_valid(raise_exception=True)
    user = serializer.save()
    return Response({
        "user": UserSerializer(user, context=self.get_serializer_context()).data,
    })

【问题讨论】:

    标签: python django django-rest-framework django-views django-serializer


    【解决方案1】:

    问题出在RegisterSerializer.create方法中:

    def create(self, data):
        user = User.objects.create(**data)
        return user
    

    您将来自用户的password 作为文本,并调用User.objects.create 来创建User 实例。 UserManagercreate 方法(最终委托给 QuerySet)是通用的,这意味着 password 字段将按原样填充为输入数据,没有任何 hashing-salting-peppering。

    由于是明文保存的,Django无法确定保存的格式(典型格式为hash_algo$iterations$salt$hash),因此无法从中找出哈希算法、salt、hash;因此错误无效的密码格式或未知的散列算法

    UserManager 公开方法 create_user 正是为了通过传递纯文本密码并在那里执行所有这些操作来创建用户,您应该利用它:

    def create(self, data):
        user = User.objects.create_user(**data)
        #                   ^^^^ Here
        return user
    

    或者您可以直接在序列化程序中的用户实例上使用set_password,但由于您可以轻松使用create_user,您应该使用它。

    【讨论】:

    • 我将其更改为 create_user() 但是,它仍然给我同样的错误。 :(
    • @user8229795 通过 API 创建一个新用户并使用该用户登录。并从数据库更新所有现有用户以设置正确的密码(使用set_password)。
    • 我删除了 db 和 migrations 仍然没有用。谢谢你的时间。 ? 有没有更简单的方法来做到这一点?但我确实想在模型中添加字段并使用不同的身份验证。
    • @user8229795 请编辑您的问题并添加您现在获得的完整回溯。
    • 我编辑了我的问题。创建时我没有错误,但是当我检查数据库时,它没有被散列。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多