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.
Passwords are hashed, by default, using the PBKDF2 algorithm. However, Django provides the option to use other algorithms such as Argon2 and bcrypt.
How To Create Your Own Django Password Validator. If you have more specific needs, you can create your own validators. To do so, simply create your own classes based on object and raise a ValidationError if the entered password fails. class NumberValidator(object): def validate(self, password, user=None): if not re.
Programmatically, you can create / save a new User without a password argument, and it will not raise any exceptions. In fact, you can even create a user without any arguments.
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With