Невозможно войти в систему, потому что Django сохраняет пароли в виде обычного текста, но

#django #django-rest-framework

#django #django-rest-framework

Вопрос:

 class UserManager(BaseUserManager):

    def create_user(self, username, email, password=None):
        if username is None:
            raise TypeError('User should have a username')
        if email is None:
            raise TypeError('User should have an email')

        user = self.model(
            username=username,
            email=self.normalize_email(email)
        )
        user.set_password(password)
        user.save(using=self._db)
        return user


    def create_superuser(self, username, email, password=None):
        if password is None:
            raise TypeError('Password should not be none')

        user = self.create_user(username, email, password)
        user.is_superuser = True
        user.is_staff = True
        user.save()
        return user



class User(AbstractBaseUser, PermissionsMixin):
    
    username = models.CharField(
        max_length = 255,
        unique = True,
        db_index = True
    )
    email = models.EmailField(
        max_length = 255,
        unique = True,
        db_index = True
    )
    is_verified = models.BooleanField(default = False)
    is_staff = models.BooleanField(default = True)
    is_active = models.BooleanField(default = True)

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = ['username']

    objects = UserManager()

    def __str__(self):
        return self.email

    def tokens(self):
        refresh = RefreshToken.for_user(self)
        return {
            'refresh': str(refresh),
            'access': str(refresh.access_token)
        }


class RegisterSerializer(serializers.ModelSerializer):

    
    password = serializers.CharField(
        max_length = 255,
        min_length = 6,
        write_only = True
    )

    class Meta:
        model = User
        fields = ['email', 'username', 'password']
        extra_kwargs = {'password': {'write_only': True, 'min_length': 5}}

        def validate(self, attrs):
            email = attrs.get('email', '')
            username = attrs.get('username', '')

            if not username.isalnum():
                raise serializers.ValidationError(
                    "Username should contain only alphanumeric characters"
                )
            return attrs


        def create(self, validated_data):
            return User.objects.create_user(**validated_data)



class RegisterView(generics.GenericAPIView):

    permission_classes = (AllowAny,)
    serializer_class = RegisterSerializer

    def post(self, request):
        serializer = self.serializer_class(data=request.data)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        user_data = serializer.data

        return Response(
            serializer.data,
            status=status.HTTP_201_CREATED
        )
 

В настоящее время я использую django 3.1.3 и djangorestframework 3.12.2 . Хотя я могу войти в систему с суперпользователем и правильно получать токены, но не смог войти в систему с помощью штатных пользователей. От администратора Django я видел, что только у суперпользователя есть хэшированный пароль, а у всех остальных пользователей есть обычный текстовый пароль.

Ответ №1:

Вы не устанавливаете пароль с user.password помощью , это просто текстовое поле в модели и работает как любое другое. Вы должны либо:

  1. предпочтительно: Позвонить user.set_password(value)
  2. резервное копирование: вычислите пароль вручную, используя make_password перед сохранением

У вас уже есть create метод, поэтому мы сначала поработаем с ним.

 from django.contrib.auth.hashers import make_password

def create(self, validated_data):
    pwd = validated_data.pop("password")
    user = User.objects.create(**attrs)
    user.set_password(pwd)
    user.save(updated_fields=["password"])
    return user

# or you could replace it in validated_data
def create(self, validated_data):
    validated_data["password"] = make_password(validated_data["password"])
    return User.objects.create(**attrs)
 

У вас есть процедура проверки, но она глобальная. Если вы укажете его конкретно в поле пароля, то сможете вычислить его там и оставить create в покое. Люди обычно этого не делают, потому что стандартно также иметь поле «подтвердить пароль».

 def validate_password(self, value):
    # ...
    return make_password(value)
 

Теперь, если вы хотите добавить confirm_password поле, вам validate(self, attrs) все равно нужно будет сравнить два поля, поэтому я бы рекомендовал отказаться от этого последнего метода.