How to Hash Django user password in Django Rest Framework?
Asked Answered
W

8

18

I'm trying to create an API for my user registration using Django Rest Framework. I created a serializer by following the step from the api-guide

class CreateUserSerializer(serializers.ModelSerializer):
  class Meta:
    model = User
    fields = ('email', 'username', 'password')
    extra_kwargs = {'password': {'write_only': True}}

  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

However, I keep getting the Invalid password format or unknown hashing algorithm. for my newly created user. I've tried to use make_password from django.contrib.auth.hashers, but I still can't resolve this issue.

Thanks

Weatherworn answered 26/12, 2016 at 14:15 Comment(1)
This might help #27586595Cystic
D
30

You can try it in this way

from django.contrib.auth.hashers import make_password

user = User.objects.create(
       email=validated_data['email'],
       username=validated_data['username'],
       password = make_password(validated_data['password'])
)
Delight answered 27/12, 2016 at 14:53 Comment(1)
For anyone spending way too much finding an answer to why user.set_password(password) this solution finally works when we're setting the password during user creation. It seems to me that I had race condition issues as I tried to create the user first via bulk_create, and set the password later.Volkslied
T
8

You can overwrite the perform_create method in CreateAPIView

from rest_framework.generics import CreateAPIView

class SignUpView(CreateAPIView):
    serializer_class = SignUpSerializers

    def perform_create(self, serializer):
        instance = serializer.save()
        instance.set_password(instance.password)
        instance.save()
Toomay answered 24/10, 2017 at 10:32 Comment(2)
this will save the instance twiceAldred
Yes, it won't be the best way to do itToomay
L
7

In the serializer redefine the function create with this:

from django.contrib.auth.hashers import make_password

class UserSerializer(ModelSerializer):

    def create(self, validated_data):
        validated_data['password'] = make_password(validated_data['password'])
        return super(UserSerializer, self).create(validated_data)

And this all! :D

Latterday answered 30/9, 2019 at 5:36 Comment(0)
D
6

You could also use a field validation function for the password field by adding a validate_password method to your serializer and make it return the hash.

from rest_framework.serializers import ModelSerializer
from django.contrib.auth.hashers import make_password


class UserSerializer(ModelSerializer):
    class Meta:
        model = backend.models.User
        fields = ('username', 'email', 'password',)

    validate_password = make_password
Decompress answered 18/2, 2019 at 17:58 Comment(0)
B
1

You can do this in the views perform_create method:

from django.contrib.auth.hashers import make_password



def perform_create(self, instance):
        current_user = self.request.user
        user_exists = CustomUser.objects.filter(
            email=self.request.data['email']).first()
        if user_exists:
            raise MethodNotAllowed
        else:
            instance.save(is_active=False, is_confirmed=False,
                          password=make_password(self.request.data['password']))
Birdcage answered 15/9, 2019 at 8:51 Comment(0)
E
0

Another simple solution is to use User.objects.create_user() in your create method like below

def create(self, validated_data):
    user = User.objects.create_user(**validated_data)
    return user
Exanimate answered 23/9, 2021 at 18:43 Comment(0)
Q
0

Another solution is to create a custom field. The advantage is that it works for both create and update. It also provides automatic documentation.

fields.py

class PasswordField(serializers.CharField):
    def __init__(self, *args, **kwargs):
        kwargs.update(
            {
                "help_text": " ".join(
                    password_validation.password_validators_help_texts()
                ),
                "max_length": 128,
                "style": {"input_type": "password"},
                "write_only": True,
            }
        )
        super().__init__(*args, **kwargs)

    def to_internal_value(self, data):
        password_validation.validate_password(data)
        return make_password(data)

serializers.py

class UserSerializer(serializers.ModelSerializer):
    password = PasswordField()

    class Meta:
        model = User
        fields = [
            "id",
            "first_name",
            "last_name",
            "email",
            "password",
        ]
Quantize answered 30/11, 2023 at 9:22 Comment(0)
A
-1

I know it's an old thread but i got this question today and i like to share my solution here.

You can define your serializer simple and like below:

class CreateUserSerializer(serializers.ModelSerializer):
    class Meta:
        model = User
        fields = ('email', 'username', 'password')
        extra_kwargs = {'password': {'write_only': True}}

on the other hand in your view you can override perform_create method as below:

class UserView(ViewSets.ModelViewSet):
    queryset = User.objects.all()
    serializer_class = UserCreateSerializer

    def perform_create(self , serializer):
        new_user = 
        User.objects.create(username=self.request.data.get("username"))
        new_user.set_password(self.request.data.get("password"))
        serializer.save(password=user.password)

in this way, you can pass extra information to serializer to save.

Atlanta answered 3/10, 2019 at 18:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.