интеграция валидаторов паролей django с Django Rest framework проверка пароля

Я пытаюсь интегрировать валидаторы django 1.9 с сериализаторами Django Rest framework. Но сериализованный "пользователь" (Django Rest framework) несовместим с валидаторами django.

вот serializers.py

import django.contrib.auth.password_validation as validators
from rest_framework import serializers

    class RegisterUserSerializer(serializers.ModelSerializer):

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

        class Meta:
            model = User
            fields = ('id', 'username', 'email, 'password')

        def validate_password(self, data):
            validators.validate_password(password=data, user=User)
            return data

        def create(self, validated_data):
            user = User.objects.create_user(**validated_data)
            user.is_active = False
            user.save()
            return user

мне удалось получить MinimumLengthValidator и NumericPasswordValidator правильно, потому что обе функции validate не используют "user" при проверке. Исходный код здесь

выдержка из django исходный код:

def validate(self, password, user=None):
        if password.isdigit():
            raise ValidationError(
                _("This password is entirely numeric."),
                code='password_entirely_numeric',
            )

для других валидаторов, таких как UserAttributeSimilarityValidator, функция использует еще один аргумент "user" при проверке ("user" - это модель пользователя django, если я не ошибаюсь)

выдержка из исходного кода django:

 def validate(self, password, user=None):
        if not user:
            return

        for attribute_name in self.user_attributes:
            value = getattr(user, attribute_name, None)

как я могу изменить сериализованного пользователя в то, что могут видеть валидаторы django(UserAttributeSimilarityValidator)

выдержка из источника django код:

def validate(self, password, user=None):
        if not user:
            return

        for attribute_name in self.user_attributes:
            value = getattr(user, attribute_name, None)
            if not value or not isinstance(value, string_types):
                continue

редактировать

Django Rest Framework может получить всю встроенную проверку пароля Django (но это похоже на взлом). Вот проблема:

validationError выглядит следующим образом

[ValidationError (['этот пароль слишком короткий. Он должен содержать в не менее 8 символов.']), ValidationError(['этот пароль полностью числовой.'])]

проверка не содержит поля. Django Rest framework видит его как

{
    "non_field_errors": [
        "This password is too short. It must contain at least 8 characters.",
        "This password is entirely numeric."
    ]
}

как я могу ввести поле в raise ValidationError

4 ответов


как вы упомянули, когда вы проверяете password на validate_password способ использования UserAttributeSimilarityValidator валидатор, у вас нет


Вы можете получить доступ к объекту пользователя через self.instance на объекте сериализатора, даже при выполнении проверки на уровне поля. Что-то вроде этого должно работать:

 from django.contrib.auth import password_validation

 def validate_password(self, value):
    password_validation.validate_password(value, self.instance)
    return value

Использовать Сериализаторы! Есть validate_fieldname способ!

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = (
            'id', 'username', 'password', 'first_name', 'last_name', 'email'
        )
        extra_kwargs = {
            'password': {'write_only': True},
            'username': {'read_only': True}
        }

    def validate_password(self, value):
        try:
            validate_password(value)
        except ValidationError as exc:
            raise serializers.ValidationError(str(exc))
        return value

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

        user.is_active = False
        user.save()
        return user

    def update(self, instance, validated_data):
        user = super().update(instance, validated_data)
        if 'password' in validated_data:
            user.set_password(validated_data['password'])
            user.save()
        return user

во время создания нового пользователя (регистрации) затем самостоятельно.экземпляр будет none, он будет работать, когда вы отдыхаете пароль, изменить пароль или обновить данные пользователя с паролем. Но если вы хотите проверить пароль не должен быть похож на вашу электронную почту или имя пользователя, то вам нужно включить " SequenceMatcher" в вашей валидации

data = self.get_initial()
username = data.get("username")
email = data.get("email")
password = data.get("password") 
max_similarity = 0.7
if SequenceMatcher(a=password.lower(), b=username.lower()).quick_ratio() > max_similarity:
    raise serializers.ValidationError("The password is too similar to the username.")
if SequenceMatcher(a=password.lower(), b=email.lower()).quick_ratio() > max_similarity:
    raise serializers.ValidationError("The password is too similar to the email.")