knirirr
knirirr

Reputation: 2829

Django password_reset, handling used URL

An app upon which I'm working will let users successfully reset their password; urls.py contains this:

url(r'^reset/(?P<uidb64>[0-9A-Za-z_\-]+)/(?P<token>.+)/$',
                       'django.contrib.auth.views.password_reset_confirm',
                       name='password_reset_confirm')

This works as expected, directing the user to such URLs as:

http://example.com/reset/MTNzgN/3ly-466604bc1524f789c120/

..where their password can be reset.

So far this isn't a problem, but if users then visit the link again (and it appears that some users have been doing this) they are presented with the same invitation to change their password, only on this occasion it won't appear to have any effect when they enter values into the boxes. This results in some confusion.

Is this Django's expected behaviour? If not, is there any means whereby I could override django.contrib.auth.views.password_reset_confirm and detect the used token there, or redirect to a warning on failure? Ideally it would be best to show them a "this token has already been used, please try to reset your password again" screen rather than a failure message after reset, but even the latter option would be better that what it does now.

Upvotes: 0

Views: 513

Answers (1)

ruddra
ruddra

Reputation: 52028

I tried like this, using Class Based View:

View:

class PasswordResetConfirmView(FormView):
    template_name = "test_template.html"
    success_url = '/account/login'
    form_class = SetPasswordForm

    def get(self, request, uidb64=None, token=None, *arg, **kwargs):
        UserModel = get_user_model()
        try:
            uid = urlsafe_base64_decode(uidb64)
            user = UserModel._default_manager.get(pk=uid)
        except (TypeError, ValueError, OverflowError, UserModel.DoesNotExist):
            user = None
        if user is not None and default_token_generator.check_token(user, token):
            return super().get(request, uidb64=None, token=None, *arg, **kwargs)

        else:
             messages.error(request,'The reset password link is no longer valid.')
            return redirect('/') 

Url:

urlpatterns += patterns('',
                       url(r'^account/reset_password_confirm/(?P<uidb64>[0-9A-Za-z]+)-(?P<token>.+)/$', PasswordResetConfirmView.as_view(),name='reset_password_confirm'),
                       )

Upvotes: 2

Related Questions