2016-04-04 18 views
5

Tôi đang cố gắng tích hợp django validators 1.9 với bộ nối tiếp khung còn lại django. Nhưng serialized 'user' (của django rest framework) không tương thích với các trình xác nhận django.tích hợp trình xác nhận mật khẩu django với khung công tác còn lại django validate_password

Đây là 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 

tôi quản lý để có được MinimumLengthValidator và NumericPasswordValidator đúng vì cả hai chức năng validate không sử dụng 'người dùng trong việc chứng thực. Mã nguồn here

Trích từ mã nguồn django:

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

Đối với xác nhận khác như UserAttributeSimilarityValidator, chức năng sử dụng một số khác tranh luận 'user' trong việc chứng thực ('sử dụng' được django mô hình dùng, nếu tôi m không sai)

Trích từ mã nguồn django:

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

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

Làm thế nào tôi có thể thay đổi serializ ed tài vào những gì django xác nhận (UserAttributeSimilarityValidator) có thể thấy

Trích từ mã nguồn 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 

Sửa

Django Nghỉ ngơi Framework có thể nhận được tất cả Django tích hợp trong xác nhận mật khẩu (nhưng nó giống như một hack). Dưới đây là một vấn đề:

Các validationError là như thế này

[ValidationError ([ 'password này là quá ngắn Nó phải chứa ít ít nhất 8 ký tự..']), ValidationError ([ 'password Đây là hoàn toàn số. '])]

Xác thực không chứa trường. Django khuôn khổ còn lại xem nó như là

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

Làm thế nào tôi có thể tiêm một thực tế tại raise ValidationError

Trả lời

8

Giống như bạn đã đề cập, khi bạn xác nhận password trong validate_password phương pháp sử dụng UserAttributeSimilarityValidator validator, bạn không phải đối tượng user.

gì tôi đề nghị rằng thay vì làm xác nhận lĩnh vực cấp, bạn thực hiện object-level validation bằng cách thực hiện validate phương pháp trên serializer:

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) 
+0

Có một vài lỗi đánh máy trong mã của bạn. Bằng cách này, giải pháp của bạn hoạt động tốt trên xác thực nhưng khung thời gian còn lại của django không thể lấy tên trường do đó non_field_errors ---> { "non_field_errors": [ "Mật khẩu quá giống với email.", " Mật khẩu này quá ngắn. Mật khẩu phải chứa ít nhất 8 ký tự. " ] } – momokjaaaaa

+0

Tôi chưa thực sự kiểm tra mã để có thể có một số lỗi chính tả ở đây và ở đó nhưng điều đó sẽ không ngăn bạn sử dụng và kiểm tra mã này đúng cách. Về 'NON_FIELD_ERRORS' tôi đã cập nhật câu trả lời của mình và bây giờ các lỗi được nêu ra phải chứa tên trường' password' làm khóa cho các lỗi đó. – AKS

+0

Ghi nhớ rằng '** dữ liệu' có thể không bao gồm tất cả các trường bắt buộc để tạo đối tượng người dùng khi thực hiện cập nhật một phần (' PATCH'). – faph

6

Bạn có thể truy cập vào đối tượng người dùng thông qua self.instance trên đối tượng serializer, ngay cả khi thực hiện xác nhận cấp trường.Một cái gì đó như thế này sẽ hoạt động:

from django.contrib.auth import password_validation 

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

Điều này sẽ chỉ khả dụng nếu người dùng đã được tạo. Điều này sẽ không xảy ra khi đăng ký người dùng mới và xác thực việc tạo mật khẩu trước. – tbm

1

Sử dụng bộ nối tiếp! Có phương thức 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): 
     validated_data = self.check_for_unique_email(validated_data) 
     validated_data.setdefault('username', validated_data['email']) 
     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): 
     validated_data = self.check_for_unique_email(validated_data) 
     user = super().update(instance, validated_data) 
     if 'password' in validated_data: 
      user.set_password(validated_data['password']) 
      user.save() 
     return user 
0

Tại thời điểm tạo người dùng mới (đăng ký) sau đó self.instance sẽ không có, nó sẽ làm việc khi của bạn được nghỉ ngơi mật khẩu, thay đổi mật khẩu hoặc cập nhật dữ liệu người dùng bằng mật khẩu. Nhưng nếu bạn muốn kiểm tra mật khẩu không nên tương tự như email hoặc tên đăng nhập của bạn thì bạn cần phải bao gồm "SequenceMatcher" trong xác nhận của bạn

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.") 
Các vấn đề liên quan