web-dev-qa-db-ja.com

DjangoパスワードバリデーターとDjango残りのフレームワークvalidate_password

私は Djangoバリデータ 1.9をDjango RESTフレームワークシリアライザと統合しようとしています。しかし、シリアル化された 'user'(Django Restフレームワーク)は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

Validateはどちらも検証に「user」を使用しないため、MinimumLengthValidatorとNumericPasswordValidatorを正しく取得できました。ソースコードは here です

Djangoソースコードからの抜粋:

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

UserAttributeSimilarityValidatorのような他のバリデーターの場合、関数は検証に別の1つの引数 '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 validators(UserAttributeSimilarityValidator)can see

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フレームワーク

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

raise ValidationErrorにフィールドを挿入するにはどうすればよいですか

17
momokjaaaaa

前述のように、passwordバリデーターを使用してvalidate_passwordメソッドでUserAttributeSimilarityValidatorを検証する場合、userオブジェクトはありません。

フィールドレベルの検証を行う代わりに、シリアライザにvalidateメソッドを実装して オブジェクトレベルの検証 を実行することをお勧めします。

import sys
from Django.core import exceptions
import Django.contrib.auth.password_validation as validators

class RegisterUserSerializer(serializers.ModelSerializer):

     # rest of the code

     def validate(self, data):
         # here data has all the fields which have validated values
         # so we can create a User instance out of it
         user = User(**data)

         # get the password from the data
         password = data.get('password')

         errors = dict() 
         try:
             # validate the password and catch the exception
             validators.validate_password(password=password, user=User)

         # the exception raised here is different than serializers.ValidationError
         except exceptions.ValidationError as e:
             errors['password'] = list(e.messages)

         if errors:
             raise serializers.ValidationError(errors)

         return super(RegisterUserSerializer, self).validate(data)
23
AKS

フィールドレベルの検証を行う場合でも、シリアライザオブジェクトのself.instanceを介してユーザーオブジェクトにアクセスできます。このようなものはうまくいくはずです:

 from Django.contrib.auth import password_validation

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

シリアライザを使用してください! 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
4
shredding

新しいユーザー(登録)を作成する時点では、self.instanceは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.")
0
Sanjay Bharti