Django REST框架用户注册?

14

我正在遵循这篇教程,但是遇到了以下问题,我无法解决:

  1. 注册用户后,我无法使用该用户登录api,因为密码未加密,在管理员中显示 "Invalid password format or unknown hashing algorithm."
  2. 当我未登录api时,我无法向“api/accounts”发帖或在可浏览的api中看到表单。

我的代码:

from django.contrib.auth.models import User
from rest_framework import serializers

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('password', 'first_name', 'last_name', 'email')
        write_only_fields = ('password',)

    def restore_object(self, attrs, instance=None):
        # call set_password on user object. Without this
        # the password will be stored in plain text.
        user = super(UserSerializer, self).restore_object(attrs, instance)
        user.set_password(attrs['password'])  #somehow not hashing
        return user

1
在DRF 3.0中,write_only_fields = ('password',) 被更改为 extra_kwargs = {'password': {'write_only': True}, } - Chemical Programmer
1
另一个好的解决方案:https://dev59.com/414c5IYBdhLWcg3w1tSO - Chemical Programmer
6个回答

13

我尝试了DRF 3.0.2中的被接受答案,但它没有起作用。密码未被散列。

相反,在您的模型序列化器中覆盖create方法。

    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

这会在使用rest框架创建用户时对密码进行哈希,而不是在post_save事件中


4
可以使用User.objects.create_user(**validated_data)创建用户(包括哈希密码),这比分两行进行操作更容易。 - aensm

6

DRF 3.X的另一种方法:

from django.contrib.auth import get_user_model
from django.contrib.auth.hashers import make_password

    def create(self, validated_data):    
        if validated_data.get('password'):
            validated_data['password'] = make_password(
                validated_data['password']
            )

        user = get_user_model().objects.create(**validated_data)

        return user

1
你很完美。 - Tolgahan ÜZÜN

3
我使用wsgeorge的解决方案来构建自己的。创建了一个空白的User对象,只是为了能够使用.set_password():
def create(self, validated_data):
    user = User()
    user.set_password(validated_data['password'])
    validated_data['password'] = user.password
    return super(UserSerializer, self).create(validated_data)

与他的答案不同,我不保存用户信息,而是将其留给调用super的父类处理。

1
请注意,set_password()不会保存对象,并且因为您已经首先调用了super,所以您的对象已经使用原始密码保存。
只需简单地使用post_save()保存密码。
def post_save(self, obj, created=False):
    """
    On creation, replace the raw password with a hashed version.
    """
    if created:
        obj.set_password(obj.password)
        obj.save()

0

重写模型序列化器的创建方法

def create(self, validated_data):
        if validated_data.get('password'):
            validated_data['password'] = make_password(validated_data['password'])
        return super(UserSerializer, self).create(validated_data)

请确保导入

from django.contrib.auth.hashers import make_password

-1
我们可以编写一个用户信号来解决这个问题。
def create_hash(sender, instance=None, *args, **kwargs):
passwd = instance.password
instance.set_password(passwd)


pre_save.connect(create_hash, sender=User)

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