I am trying to use token authentication, but it is not working due to my create user serializer not hashing the passwords. I am able to login with the superuser as that has a hashed password. Using rest_auth and rest_framework.authtoken. The user.set_password command is supposed to hash the password, so is there an issue with the prior code?
class CreateUserSerializer(serializers.HyperlinkedModelSerializer):
username = serializers.CharField()
password = serializers.CharField(write_only = True, style = {'input_type': 'password'})
class Meta:
model = get_user_model()
fields = (
'id','username', 'password',
'email', 'first_name', 'last_name'
)
write_only_fields = ('password')
read_only_fields = ('is_staff', 'is_superuser', 'is_active')
def create(self, validated_data):
password = validated_data.pop('password')
user = super().create(validated_data)
user.set_password(validated_data['password'])
user.save()
return user
class CreateUserAPIView(CreateAPIView):
"""
Create a new user.
"""
serializer_class = CreateUserSerializer
permission_classes = [AllowAny]
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data = request.data)
serializer.is_valid(raise_exception = True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
# Create a token that will be used for future auth
token = Token.objects.create(user = serializer.instance)
token_data = {"token": token.key}
return Response(
{**serializer.data, **token_data},
status = status.HTTP_201_CREATED,
headers = headers
)
AUTH_PASSWORD_VALIDATORS = [
{
'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
},
{
'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
},
]
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.TokenAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = (
'url', 'username', 'email', 'groups', 'workflow_step',
'first_name', 'last_name',
'birthdate',
'address_street1', 'address_street2', 'address_city',
'address_state', 'address_postal_code', 'address_country', 'phone'
)
class User(AbstractUser):
# Application process
workflow_step = models.CharField(max_length=100, default='', blank=True)
is_verified = models.BooleanField(default=False)
# Basic information
# first_name (in django.contrib.auth.models.User)
# last_name (in django.contrib.auth.models.User)
# email (in django.contrib.auth.models.User)
# Advanced Information
birthdate = models.DateField(blank=True, null=True)
address_street1 = models.CharField(max_length=100, blank=True)
address_street2 = models.CharField(max_length=100, default='', blank=True)
address_city = models.CharField(max_length=100, blank=True)
address_state = models.CharField(max_length=50, blank=True)
address_postal_code = models.CharField(max_length=30, blank=True)
address_country = models.CharField(max_length=100, blank=True)
phone = models.CharField(max_length=30, blank=True)
This is probably too late, but for anyone who has this issue. you need to put the create
function directly inside the serializer class, in your case you have it in the Meta
subclass
The second thing you need to do is to use
def create(self, validated_data):
password = validated_data.pop('password')
user = super().create(validated_data)
user.set_password(password)
user.save()
return user
best of luck