简体   繁体   中英

In Django's auth contrib module, how do I validate a token submitted from a reset password form?

I'm using Django 3.1 with its auth contrib module. I have an API-only application, in which I initiate a password reset using the following Django view

class ResetPasswordView(SuccessMessageMixin, PasswordResetView):
    reset_password_template_name = 'templates/users/password_reset.html'
    email_template_name = 'users/password_reset_email.html'
    subject_template_name = 'users/password_reset_subject'
    success_message = "We've emailed you instructions for setting your password, " \
                      "if an account exists with the email you entered. You should receive them shortly." \
                      " If you don't receive an email, " \
                      "please make sure you've entered the address you registered with, and check your spam folder."
    success_url = reverse_lazy('users-home')

    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        request.csrf_processing_done = True
        return super().dispatch(request, *args, **kwargs)

    def post(self, request, *args, **kwargs):
        email = json.loads(request.body).get('username')
        try:
            if User.objects.get(email=email).is_active:
                form = PasswordResetForm({'email': email})
                print("form valid? %s" % form.is_valid())
                if form.is_valid():
                    request = HttpRequest()
                    request.META['SERVER_NAME'] = socket.gethostbyname('localhost') #'127.0.0.1'
                    request.META['SERVER_PORT'] = 8000
                    # calling save() sends the email
                    # check the form in the source code for the signature and defaults
                    form.save(request=request,
                        use_https=False,
                        from_email="laredotornado@yahoo.com",
                        email_template_name='../templates/users/password_reset_email.html')
                print("email: %s " % email)
                return super(ResetPasswordView, self).post(request, *args, **kwargs)
        except Exception as e:
            print("\n\nerror ...\n\n")
            print(e)
            # this for if the email is not in the db of the system
            return super(ResetPasswordView, self).post(request, *args, **kwargs)

This generates an email in which a link appears, which looks similar to

http://127.0.0.1:8000/password-reset-confirm/Mg/bhd3nc-29fa9003c9c61c2bda5cff0a66b38bdf/

My question is, how do I submit this token (with the user's desired new password) back to the server so that the srver validates the token anad then updates the password for the user?

It depends on the authentication strategy implemented with your API. From the fact that you are sending a user a token, I assume that you are using token authentication. :) It means that on the API side you need to implement password reset endpoint with token authentication. Do not forget to expire/blacklist the token.

Another strategy would be to run the password reset process using Django password reset views, without messing up with the API.

Reuse django.contrib.auth.views.PasswordResetConfirmView , which calls self.token_generator.check_token(self.user, session_token) .

import json

from django.contrib.auth.views import INTERNAL_RESET_SESSION_TOKEN, PasswordResetConfirmView
from django.views.decorators.csrf import csrf_exempt


class ConfirmResetPasswordView(PasswordResetConfirmView):

    @csrf_exempt
    def dispatch(self, request):
        data = self.data = json.loads(request.body)
        # self.user = self.get_user(data["uidb64"])
        # self.token_generator.check_token(self.user, data['token'])
        self.request.session[INTERNAL_RESET_SESSION_TOKEN] = data.pop('token')
        data['token'] = self.reset_url_token
        return super().dispatch(request, **data)

    def get_form_kwargs(self):
        return {
            'data': self.data,
            'user': self.user,
        }

Sample POST request body:

{
    "uidb64": "Mg",
    "token": "bhd3nc-29fa9003c9c61c2bda5cff0a66b38bdf",
    "new_password1": "new_password",
    "new_password2": "new_password"
}

Generate a unique token and send it along with the user's ID in a URL to the user's email address. The user clicks the URL and is redirected to a page where they can input a new password. The password and the token are sent back to the server and validated. The token is checked to make sure it belongs to the correct user and has not expired. If the token is valid, the password is updated for the user.

example first create a URL like

reset_password_link = f"http://localhost:8000/reset_password/{reset_password_token}?user_id={user.id}"
    # send email with reset_password_link to user's email address
    
    and then send this in mail and in reset_password page create a form which take new password and then validate it. 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM