2

I'm trying to implement password reset by sending an email to the user with a link which will redirect him/her to a new password form.

I took by example this question and this site.

But my problem is a bit different. I don't have a local database containing the users, so I cannot perform operations over their attributes. I receive user data via an API (user id, user email, user password).

So, which is the best way to generate a unique link to send via email to user so that this link would tell me who the user is and allow me to reset his/her password? And also, how could I redirect it in urls.py? I wish that this link could be used only a single time.

My views.py is like this:

def password_reset_form(request):

if request.method == 'GET':
    form = PasswordResetForm()
else:
    form = PasswordResetForm(request.POST) 

    if form.is_valid():
        email = form.cleaned_data['email']

        content_dict = {
            'email': email,
            'domain': temp_data.DOMAIN,
            'site_name': temp_data.SITE_NAME,
            'protocol': temp_data.PROTOCOL,
            }

        subject = content_dict.get('site_name')+ ' - Password Reset'
        content = render_to_string('portal/password_reset_email.html', content_dict)
        send_mail(subject, content, temp_data.FIBRE_CONTACT_EMAIL, [email])

        return render(request, 'portal/password_reset_done.html', {'form': form,})

return render(request, 'portal/password_reset_form.html', {'form': form,})

And the template the e-mail I'm sending is:

{% autoescape off %}

You're receiving this e-mail because we got a request to reset the password for your user account at {{ site_name }}.

Please go to the following page and choose a new password:

{% block reset_link %}
{{ protocol }}://{{ domain }}/[***some unique link***]
{% endblock %}

If you didn't request a password reset, let us know. 

Thank you.

The {{ site_name }} team.

{% endautoescape %}

Thanks, guys.

1
  • @KlausD., no it's a salt of the password. Commented Sep 16, 2016 at 20:03

3 Answers 3

2

Don't reinvent the wheel. You should use django-allauth for this kind of stuff. The library is well maintained and under active development.

Sign up to request clarification or add additional context in comments.

Comments

1

The problem is not to generate unique link, you need to store somewhere info about user id or email, and generated token. Otherwise you will not know which user should use which token. After user resets his password you can delete his record (his token).

You can write the most simple model even in sqlite, which basically could look like this:

class UserTokens(model.Models):
    email = models.EmailField(max_length=50)
    token = models.CharField(max_length=50)

Afterwards when you send mail make something like this:

def password_reset_form(request):

    #your logic here
    # form post

    usr, created = UserToken.objects.get_or_create(email=form.email)
    if usr.token:
        #send this token to him
     else:
        usr.token = ''.join(
    random.choice(string.ascii_uppercase + string.digits) for _ in range(50))
         usr.save()
         #also send this token to him

Then you create a new view or api view which searches for that token, if found, let him reset the password. If not, raise a 404 error, or just let him know that there is no such link to reset password.

Please not that, this was written from my phone so care for typos.

PS. you also asked about urls

just make something like this:

url(r'unsubscribe/(?P<quit_hash>[\w\d]+)/$', 'quit_newsletter_or_somethin', name='quit_newsletter_or_somethin')

2 Comments

The approach described in this answer has the following issues: 1 Explicit token deletion must happen right after use, if any error prevents that from happening then password reset token can be reused. 2 Tokens are better stored well-hashed and salted, just like passwords (one reason why). 3 As Python docs on random state, it shouldn’t be used for security purposes. Heed the warning! Django uses vanilla random only as fallback and seeds it first.
Yes @AntonStrogonoff I agree, like I said, this answer was written with a phone. But this is just a general idea, an approach, which can be used and further on developed.
1

I’d suggest to borrow the general logic from Django and adapt it to your specific conditions:

As you can see from PasswordResetTokenGenerator._make_token_with_timestamp(), its algo relies on user’s last login timestamp, so the APIs you consume would need to accommodate that.

You could import the same utility functions used by the above—where cryptography is concerned it’s better to rely on well-tested solutions. Deep internals are prone to change without a release note though when you update to newer Django versions, so take care.

You could also look into simply storing some carefully randomly generated reset codes along with usernames in your local DB and deleting them when user accesses the reset form, but that is less elegant while being more brittle and infosec-issue prone.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.