python - UserManager 中的 Django set_password() 方法正在保存纯文本

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

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

模型.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

查看.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,
    })

最佳答案

问题出在 RegisterSerializer.create 方法中:

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

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

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

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

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

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

关于python - UserManager 中的 Django set_password() 方法正在保存纯文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58838108/

相关文章:

reactjs - 从 React 前端使用 DRF 上传图像

python Pandas DF : adding to one column depending on the value in that row in another column

python - 打包并克隆 Python venv

python - 如何从 seaborn 的 KDE distplot 对象中提取垃圾箱?

django - 构建用于添加对象的两阶段 Django 管理表单?

django-rest-framework - django-rest进度条上传

python - 无法从 Windows 10 卸载 python 2.7.10

django - 有没有一种方法可以优雅地在 django 中的所有外键和多对多字段中设置 "swap"行?

python - 从 Django Webserver 在远程服务器上运行脚本

python - Django REST 框架 : how to substitute null with empty string?