Lysandros Nikolaou
Lysandros Nikolaou

Reputation: 338

Django User password not getting hashed for custom users

I am currently implementing the authentication for a Django application, I am writing. Following code of the Thinkster Django course, I implemented the whole registration process, but I cannot login, because the password is not getting hashed, when registering a user.

Here is my custom User model and the create_user function.

class UserManager(BaseUserManager)
    def create_user(self, username, email, password=None):

        if username is None:
            raise TypeError('Users must have a username.')

        if email is None:
            raise TypeError('Users must have an email address.')

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

        return user

    def create_superuse(self, username, email, password):
        if password is None:
            raise TypeError('Superusers must have a password.')

        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(db_index=True, max_length=255, unique=True)
    email = models.EmailField(db_index=True, unique=True)
    is_active = models.BooleanField(default=True)
    is_staff = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

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

    objects = UserManager()

As you can see, I am explicitly calling the set_password function but I cannot find out, why it does not get properly executed?

My Serializer, where I create the user is as follows:

class RegistrationSerializer(serializers.ModelSerializer):

    password = serializers.CharField(
        max_length=128,
        min_length=8,
        write_only=True
    )

token = serializers.CharField(max_length=255, read_only=True)

class Meta:
    model = User
    fields = ['email', 'username', 'password', 'token']

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

Please note that instead of return User.objects.create_user(**validated_data), I also tried doing return get_user_model().objects.create_user(**validated_data), as it was a suggestion at another question, but that did not work either.

I also post my view, in case something is wrong there, but I really don't think that's the case.

class RegistrationAPIView(APIView):
    permission_classes = (AllowAny,)
    renderer_classes = (UserJSONRenderer,)
    serializer_class = RegistrationSerializer

    def post(self, request):
        user = request.data.get('user', {})

        serializer = self.serializer_class(data=user)
        serializer.is_valid(raise_exception=True)
        serializer.save()

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

Side Note: In case that is relevant, I am sending requests with Postman and all the responses I get back seem completely right. But when I browse my SQLite, I see that the password was not hashed. That also results in the users not being able to log in, because in the login process the password gets hashed and then compared with the one in the database.

Side Note 2: When I register a user via the command line with python manage.py createsuperuser, it gets a hashed password and everything works as I would normally expect.

Upvotes: 8

Views: 4936

Answers (3)

JillianSN
JillianSN

Reputation: 73

I think Surajano is onto something. I don't know if this will solve your problem, but I ran into the same problem a while back with creating a super user not hashing the password.

How I solved it:

def create_superuser(self, email, first_name, last_name, password):
    user = self.create_user(
        email,
        first_name,
        last_name,
        password=password,
    )

you have to explicitly set password=password

Also, I see a typo in your def create_superuser (you have it as def create_superuse) which might cause you some trouble later.

Anyhow I posted a question on this and the solution, you can check it out here:

UserCreateForm bypassing UserManager, regular users created through UserCreateForm CAN authenticate but superuser created in shell CAN NOT?

Again I don't know if this will help you or not but hope it will give you an idea on tracking down a solution at least. My example isn't using token based auth - so no serializer - but I don't think that matters since those are likely unrelated.

Upvotes: 0

Surajano
Surajano

Reputation: 2688

What I mean in the above comment of make_password is to add the following in the create_user method:

from django.contrib.auth.hashers import make_password


def create_user(self, username, email, password=None):

    if username is None:
        raise TypeError('Users must have a username.')

    if email is None:
        raise TypeError('Users must have an email address.')

    user = User.objects.create(
       email=email,
       username=username,
       password = make_password(password))

    return user

Upvotes: 4

Jan Giacomelli
Jan Giacomelli

Reputation: 1339

You need to use set_password method like this in serializer:

def create(self, validated_data):
        user = User(email=validated_data['email'], username=validated_data['username'])
        user.set_password(validated_data['password'])
        user.save()
        return user

Upvotes: 3

Related Questions