Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest change users password view

I am using Django Rest to create a simple API.I need to create a view where the user can change his/hers password.I am using the default Django user model and a simple UserSerializer. There is method called set_password but i cant find a way the use it corrently with the user seriliazer.I cant find any solution anywhere.

UserSelializer:

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ('id', "username", 'email', 'first_name', 'last_name', 'password')

View(ClassedBased): Here is an example (i have no idea what i am doing here):

    class UserChangePassword(APIView):

        def patch(self, request):
            user = self.request.user
            serialized = UserSerializer(data=request.DATA)
            if serialized.is_valid():
                user.set_password(serialized.data['password'])
                user.save()
                return Response(status=status.HTTP_205_RESET_CONTENT)
            else:
            return Response(serialized.errors, status=status.HTTP_400_BAD_REQUEST)

Mind that i want to post a json script to change to password. Something like this :

 {
    "old_password": "123", 
    "new_password": "12345"
}
like image 262
user3418042 Avatar asked Apr 24 '14 17:04

user3418042


People also ask

How can I see my password in Django?

In order to use the built-in Django check_password() function, we need to import it, which is shown in the first line of code. So the current password of the user is, request. user. password, which we store in the currentpassword variable.

What is HyperlinkedModelSerializer in Django?

HyperlinkedModelSerializer is a layer of abstraction over the default serializer that allows to quickly create a serializer for a model in Django. Django REST Framework is a wrapper over default Django Framework, basically used to create APIs of various kinds.

How does Django hash password?

Passwords are hashed, by default, using the PBKDF2 algorithm. However, Django provides the option to use other algorithms such as Argon2 and bcrypt.


2 Answers

One method could be to override the restore_object method in the Serializer. This would look something like this:

class UserSerializer(serializers.ModelSerializer):

    class Meta:
        model = User
        fields = ('id', "username", 'email', 'first_name', 'last_name', 'password')

    # turn text to hashed password
    def restore_object(self, attrs, instance=None):
        attrs['password'] = make_password(attrs['password'])
        return super(UserSerializer, self).restore_object(attrs, instance=None)

Now, when this deserializes into an object instance, you will have a valid hashed password. You should then be able to accomplish what you desire by modifying the view you currently have by just a bit.

   class UserChangePassword(APIView):

       def patch(self, request):
           serialized = UserSerializer(data=request.DATA)
           if serialized.is_valid():
               serialized.save()
               return Response(status=status.HTTP_205_RESET_CONTENT)
           else:
               return Response(serialized.errors, status=status.HTTP_400_BAD_REQUEST)

And I believe the JSON in your PATCH request would (depending on the look up type, which I think defaults to id) look something like this:

{
  "id": "83",
  "password": "12345"
}

I hope this helps!


EDIT:

Please note that as Symmetric has pointed out in the comments, restore_object has been deprecated in DRF 3.0

like image 170
jnishiyama Avatar answered Sep 22 '22 05:09

jnishiyama


Password reset using Viewset

In View

from rest_framework.decorators import detail_route, list_route, permission_classes
from rest_framework import viewsets
class UserProfileViewSet(viewsets.ViewSet):

    permission_classes = (AllowAny,)
    serializer_class = UserProfileSerializer

    def list(self, request):
        queryset = UserProfile.objects.all()
        serializer = self.serializer_class(queryset, many=True)
        return Response(serializer.data)

    def create(self, request):
        serializer = self.serializer_class(data=request.data)
        # check email address is exists or not.
        user_type = request.data['user_type']
        user_token = register_by_social(request.data['email'], request.data['username'], user_type)

        if not user_token or user_token == True:
            if not User.objects.filter(Q(email=request.data['email']) 
                | Q(username=request.data['username'])).exists():

                if serializer.is_valid():
                    userprofile = serializer.save()

                    return Response({
                        'status': status.HTTP_201_CREATED,
                        'message': 'Successfully signup new user.',
                        'token': userprofile.user.auth_token.key })

                return Response({
                    'status': status.HTTP_400_BAD_REQUEST,
                    'message': 'Please provided required fields.',
                    'error' : serializer.errors })

            return Response({
                'status': status.HTTP_409_CONFLICT,
                'message': 'Email address or username is already exists.'})

        return Response({
            'status': status.HTTP_200_OK,
            'message': 'Social user is already registered.',
            'token': user_token })

    @list_route(permission_classes=[IsAuthenticated], authentication_classes = (BasicAuthentication, TokenAuthentication), 
            methods=['post'], url_path='reset-user-password')
    def reset_user_password(self, request, pk=None):

        reset_password_serializer = UserResetPasswordSerializer(request.user, data=request.data)

        if reset_password_serializer.is_valid():

            if not request.user.check_password(request.data.get('password')):
                return Response({"password": ["Wrong password."]}, status=status.HTTP_400_BAD_REQUEST)

            request.user.set_password(request.data.get('new_password'))
            request.user.save()
            return Response({"Message": ["Password reset successfully"]}, status=status.HTTP_200_OK)

You can make a serializer only for password in serializer.py

import django.contrib.auth.password_validation as validators
class UserResetPasswordSerializer(serializers.ModelSerializer):
    password = serializers.CharField(source='user.password', style={'input_type': 'password'},
        max_length=20, min_length=8)
    new_password = serializers.CharField(style={'input_type': 'password'},
        max_length=20, min_length=8)
    class Meta:
        model = User
        fields =("password", 'new_password')
like image 45
Vinay Kumar Avatar answered Sep 23 '22 05:09

Vinay Kumar