一尘不染

为什么我的Django用户模型的密码没有散列?

django

我正在使用Django REST Framework(DRF)创建一个可以注册新用户的终结点。但是,当我通过POST到达创建端点时,新用户将通过序列化器保存,但密码以明文形式保存在数据库中。我的序列化器的代码如下:

from django.contrib.auth import get_user_model
from rest_framework import serializers

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = get_user_model()
        fields = ['password', 'username', 'first_name', 'last_name', 'email']
        read_only_fields = ['is_staff', 'is_superuser']
        write_only_fields = ['password']

请注意,我使用的是Django auth包中的默认用户模型,并且对使用DRF来说是一个新手!


阅读 462

收藏
2020-04-03

共1个答案

一尘不染

问题是DRF只需将字段值设置到模型上即可。因此,密码在“密码”字段中设置,并保存在数据库中。但是要正确设置密码,你需要调用该set_password()方法,该方法将进行哈希处理。

有几种方法可以做到这一点,但是在REST Framework v3上最好的方法是覆盖序列化器上的update()create()方法。

class UserSerializer(serializers.ModelSerializer):
    # <Your other UserSerializer stuff here>

    def create(self, validated_data):
        password = validated_data.pop('password', None)
        instance = self.Meta.model(**validated_data)
        if password is not None:
            instance.set_password(password)
        instance.save()
        return instance

    def update(self, instance, validated_data):
        for attr, value in validated_data.items():
            if attr == 'password':
                instance.set_password(value)
            else:
                setattr(instance, attr, value)
        instance.save()
        return instance

这里有两件事:

  1. 我们使用self.Meta.model,因此,如果在序列化程序上更改了模型,则它仍然可以工作(只要有某种set_password 方法就可以了)。
  2. 我们迭代validated_data项目而不是字段,以说明可选的excludeed字段。
    另外,此版本的create不会保存M2M关系。在你的示例中不需要,但是可以根据需要添加。你将需要从字典中弹出这些文件,保存模型并随后进行设置。

FWIW,因此,我将这个答案中的所有python代码设为全球公共域。它的分发没有任何保证。

2020-04-03