интеграция валидаторов паролей 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.")