简体   繁体   English

Django-Rest-Framework 自定义用户没有散列密码(序列化程序问题)

[英]Django-Rest-Framework Custom User not Hashing Password (Serializer Issue)

I am trying to use token authentication, but it is not working due to my create user serializer not hashing the passwords.我正在尝试使用令牌身份验证,但由于我的创建用户序列化程序没有对密码进行哈希处理,它无法正常工作。 I am able to login with the superuser as that has a hashed password.我可以使用超级用户登录,因为它有一个散列密码。 Using rest_auth and rest_framework.authtoken.使用 rest_auth 和 rest_framework.authtoken。 The user.set_password command is supposed to hash the password, so is there an issue with the prior code? user.set_password 命令应该对密码进行哈希处理,那么之前的代码有问题吗?

class CreateUserSerializer(serializers.HyperlinkedModelSerializer):
    username = serializers.CharField()
    password = serializers.CharField(write_only = True, style = {'input_type': 'password'})

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

        def create(self, validated_data):
            password = validated_data.pop('password')
            user = super().create(validated_data)
            user.set_password(validated_data['password'])
            user.save()
            return user
class CreateUserAPIView(CreateAPIView):
    """
    Create a new user.
    """
    serializer_class = CreateUserSerializer
    permission_classes = [AllowAny]

    def create(self, request, *args, **kwargs):
        serializer = self.get_serializer(data = request.data)
        serializer.is_valid(raise_exception = True)
        self.perform_create(serializer)
        headers = self.get_success_headers(serializer.data)

        # Create a token that will be used for future auth
        token = Token.objects.create(user = serializer.instance)
        token_data = {"token": token.key}

        return Response(
            {**serializer.data, **token_data},
            status = status.HTTP_201_CREATED,
            headers = headers
        )
AUTH_PASSWORD_VALIDATORS = [
    {
        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
    },
    {
        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
    },
]

REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 20,

    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
    ),

    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    )
}
class UserSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = User
        fields = (
            'url', 'username', 'email', 'groups', 'workflow_step',
            'first_name', 'last_name', 
            'birthdate',
            'address_street1', 'address_street2', 'address_city', 
            'address_state', 'address_postal_code', 'address_country', 'phone'
        )
class User(AbstractUser):
    # Application process
    workflow_step = models.CharField(max_length=100, default='', blank=True)

    is_verified = models.BooleanField(default=False)

    # Basic information
    # first_name (in django.contrib.auth.models.User)
    # last_name (in django.contrib.auth.models.User)
    # email (in django.contrib.auth.models.User)

    # Advanced Information
    birthdate = models.DateField(blank=True, null=True)
    address_street1 = models.CharField(max_length=100, blank=True)
    address_street2 = models.CharField(max_length=100, default='', blank=True)
    address_city = models.CharField(max_length=100, blank=True)
    address_state = models.CharField(max_length=50, blank=True)
    address_postal_code = models.CharField(max_length=30, blank=True)
    address_country = models.CharField(max_length=100, blank=True)
    phone = models.CharField(max_length=30, blank=True)

This is probably too late, but for anyone who has this issue.这可能为时已晚,但对于任何有此问题的人来说。 you need to put the create function directly inside the serializer class, in your case you have it in the Meta subclass您需要将create函数直接放在序列化程序类中,在您的情况下,您将它放在Meta子类中

The second thing you need to do is to use您需要做的第二件事是使用

def create(self, validated_data):
    password = validated_data.pop('password')
    user = super().create(validated_data)
    user.set_password(password)
    user.save()
    return user

best of luck祝你好运

In CreateUserSerializer.create you're doing this:CreateUserSerializer.create你这样做:

        password = validated_data.pop('password')
        ...
        user.set_password(validated_data['password'])

By the time you call set_password the password key has been removed from validated_data .当您调用set_password时, password密钥已从validated_data中删除。 You probably want to change the set_password line to this instead:您可能希望将set_password行改为:

        user.set_password(password)

You can use the make_passowrd function in order of hashing it:您可以使用make_passowrd函数按散列顺序:

class CreateUserSerializer(serializers.HyperlinkedModelSerializer):
    username = serializers.CharField()
    password = serializers.CharField(write_only = True, style = {'input_type': 'password'})

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

        def create(self, validated_data):
            password = validated_data.pop('password')
            user = super().create(validated_data)
            user.set_password( make_password(validated_data['password']))
            user.save()
            return user

Read all about password managing here 在此处阅读有关密码管理的所有信息

You are removing the 'password' key before hashing it.您在散列之前删除了“密码”键。 You need to change user.set_password(validated_data['password']) this to user.set_password(password) as you popped that from validated data and stored to password variable.您需要将user.set_password(validated_data['password'])更改为user.set_password(password)从验证数据中弹出并存储到密码变量。

This works for me..try this这对我有用..试试这个

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM