Reputation: 375
I am using Django with React, I am implementing a method to reset user password when users forget their password. My basic idea is to:
1) Users give their email address
2) Send an email to their email adress with the link to reset their password(with SendGrid api)
3) Users type in new password to reset their password
below is my serializers, views, urls and React code
//views.py
class PasswordResetConfirmSerializer(serializers.Serializer):
new_password1 = serializers.CharField(max_length=128)
new_password2 = serializers.CharField(max_length=128)
uid = serializers.CharField()
token = serializers.CharField()
set_password_form_class = SetPasswordForm
def custom_validation(self, attrs):
pass
def validate(self, attrs):
self._errors = {}
try:
self.user = UserModel._default_manager.get(pk=attrs['uid'])
except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
raise ValidationError({'uid': ['Invalid value']})
self.custom_validation(attrs)
self.set_password_form = self.set_password_form_class(
user=self.user, data=attrs
)
if not self.set_password_form.is_valid():
raise serializers.ValidationError(self.set_password_form.errors)
return attrs
def save(self):
return self.set_password_form.save()
// serializers.py
class PasswordResetConfirmView(GenericAPIView):
serializer_class = PasswordResetConfirmSerializer
permission_classes = (AllowAny,)
@sensitive_post_parameters_m
def dispatch(self, *args, **kwargs):
return super(PasswordResetConfirmView, self).dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
serializer.save()
return Response(
{"detail": ("Password has been reset with the new password.")}
)
//urls.py
path('api/passwordreset/confirm/',views.PasswordResetConfirmView.as_view(), name = 'password_reset_confirm')
// React
const config = {
headers: {
"Content-Type": "application/json"
}
};
const body = JSON.stringify({
new_password1: this.state.new_password,
new_password2: this.state.confirm_password,
uid: this.state.fetched_data.pk,
token: this.state.fetched_data.token
})
axios.post(API_URL + 'users/api/passwordreset/confirm/', body, config)
My reset password function itself works fine. But the main problem I am having here is that the reset password API requires 'uid' and 'token'. In order to get these two values, users have to be either logged in, which makes no sense since they forget their password, or to call an api to get the 'uid' and the 'token'. I tried the below method to get those two values:
// views.py
class CustomObtainAuthToken(ObtainAuthToken):
def post(self, request, *args, **kwargs):
response = super(CustomObtainAuthToken, self).post(request, *args, **kwargs)
token = Token.objects.get(key=response.data['token'])
return Response({'token': token.key, 'id': token.user_id})
// urls.py
path('api/authenticate/', CustomObtainAuthToken.as_view())
// React
const body = {
password: 'mike',
username: 'Abcd1234'
}
await axios.post(API_URL + 'users/api/authenticate/', body)
The function does return the corret 'uid' and 'token', but the problem is that the only thing I am getting from the user is the email address. There is no way for me to also get the password and username to call this API. So I am not really sure how to do this.
Can someone show me the correct way to make this work? Thanks a lot.
Upvotes: 4
Views: 5170
Reputation: 5742
First of all, you can get the uid
from the user's email who requested the password reset flow. And secondly this token is not the same token of your authenticated user. This token can be generated with django's default_token_generator
.
email
/api/password_reset/
) with that email
user
's email
it is and thus gets an uid
token
for that user
uid
and token
as part of it (for example, https://example.com/password-reset-confirm/<uid>/<token>
)password
(notice here: this url contains an uid and a token that will be used later)password
/api/password_reset_confirm/
) with the newly given password, along with the uid
and token
(which were part of the url)uid
, token
and new password
uid
and token
are valid (i.e. the token
matches the one it previously generated for the same user
of that uid
)user
of that uid
Since you are using DRF, take a look at the implementation of an authentication library named Djoser. It can be a good learning experience.
Upvotes: 9