【问题标题】:Django Password Reset Via Email通过电子邮件重置 Django 密码
【发布时间】:2017-01-25 03:10:28
【问题描述】:

我正在尝试通过向用户发送带有链接的电子邮件来实现密码重置,该链接会将他/她重定向到新的密码表单。

我以this questionthis site 为例。

但我的问题有点不同。我没有包含用户的本地数据库,因此我无法对其属性执行操作。我通过 API 接收用户数据(用户 ID、用户电子邮件、用户密码)。

所以,这是生成唯一链接以通过电子邮件发送给用户的最佳方式,以便此链接告诉我用户是谁并允许我重置他/她的密码?还有,我如何在 urls.py 中重定向它? 我希望这个链接只能使用一次。

我的views.py是这样的:

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,})

我发送的电子邮件的模板是:

{% 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 %}

谢谢各位。

【问题讨论】:

  • @KlausD.,不,这是密码的盐。

标签: python django django-forms


【解决方案1】:

不要重新发明轮子。您应该使用django-allauth 来处理这类事情。该库维护良好,正在积极开发中。

【讨论】:

    【解决方案2】:

    问题不在于生成唯一链接,您需要在某处存储有关用户 ID 或电子邮件的信息,以及生成的令牌。否则你将不知道哪个用户应该使用哪个令牌。用户重置密码后,您可以删除他的记录(他的令牌)。

    你甚至可以在 sqlite 中编写最简单的模型,基本上可以是这样的:

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

    之后,当您发送邮件时,请执行以下操作:

    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
    

    然后您创建一个新视图或 api 视图来搜索该令牌,如果找到,让他重置密码。如果没有,提出 404 错误,或者只是让他知道没有重置密码的链接。

    请不要这样,这是从我的手机写的,所以请注意拼写错误。

    PS。您还询问了网址

    做这样的事情:

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

    【讨论】:

    • 此答案中描述的方法存在以下问题:1 显式令牌删除必须在使用后立即进行,如果任何错误阻止了这种情况的发生,则可以重用密码重置令牌. 2 像密码(one reason why) 一样,令牌更好地存储在散列和加盐中。 3 作为random 状态的 Python 文档,它不应该用于安全目的。注意警告! Django uses vanilla random only as fallback and seeds it first.
    • 是的@AntonStrogonoff 我同意,就像我说的,这个答案是用手机写的。但这只是一个普遍的想法,一种方法,可以使用并进一步发展。
    【解决方案3】:

    我建议借用 Django 的一般逻辑并根据您的具体情况进行调整:

    PasswordResetTokenGenerator._make_token_with_timestamp() 可以看出,它的算法依赖于用户的最后登录时间戳,因此您使用的 API 需要适应这种情况。

    您可以导入与上述相同的实用程序函数 — 在涉及密码学的情况下,最好依赖经过充分测试的解决方案。但是,当您更新到较新的 Django 版本时,如果没有发布说明,深层内部结构很容易发生变化,所以要小心。

    您还可以考虑简单地将一些仔细随机生成的重置代码与用户名一起存储在本地数据库中,并在用户访问重置表单时将其删除,但这不太优雅,而且更脆弱且容易出现信息安全问题。

    【讨论】:

      猜你喜欢
      • 2018-05-24
      • 1970-01-01
      • 2010-11-21
      • 2020-02-15
      • 2012-03-09
      • 2015-06-29
      • 2013-12-18
      • 1970-01-01
      • 2019-05-01
      相关资源
      最近更新 更多