Python Django通过电子邮件重置密码

Python Django通过电子邮件重置密码,python,django,django-forms,Python,Django,Django Forms,我试图通过向用户发送一封带有链接的电子邮件来实现密码重置,该链接会将用户重定向到新的密码表单 我以身作则 但我的问题有点不同。我没有包含用户的本地数据库,因此无法对其属性执行操作。我通过API用户id、用户电子邮件和用户密码接收用户数据 那么,哪种方法是生成通过电子邮件发送给用户的唯一链接的最佳方法,以便该链接可以告诉我用户是谁,并允许我重置他/她的密码?还有,我如何在URL.py中重定向它? 我希望这个链接只能使用一次 My views.py是这样的: def password_reset_f

我试图通过向用户发送一封带有链接的电子邮件来实现密码重置,该链接会将用户重定向到新的密码表单

我以身作则

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

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

My 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,})
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
url(r'unsubscribe/(?P<quit_hash>[\w\d]+)/$', 'quit_newsletter_or_somethin', name='quit_newsletter_or_somethin')
我发送的电子邮件模板是:

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

谢谢,伙计们。

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

-有很好的文档记录,非常有用 不过,可能是已知的信息 正如您可以从PasswordResetTokenGenerator中看到的那样,它的算法依赖于用户的最后一次登录时间戳,因此您使用的API需要适应这一点

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


您也可以简单地将一些随机生成的重置代码与用户名一起存储在本地数据库中,并在用户访问重置表单时删除它们,但这样做不太优雅,同时更容易出现脆弱和信息安全问题。

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

您甚至可以在sqlite中编写最简单的模型,基本上可以如下所示:

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,})
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
url(r'unsubscribe/(?P<quit_hash>[\w\d]+)/$', 'quit_newsletter_or_somethin', name='quit_newsletter_or_somethin')
之后,当您发送邮件时,请执行以下操作:

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,})
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
url(r'unsubscribe/(?P<quit_hash>[\w\d]+)/$', 'quit_newsletter_or_somethin', name='quit_newsletter_or_somethin')
然后创建一个新的视图或api视图来搜索该令牌,如果找到,让他重置密码。如果没有,则引发404错误,或者让他知道没有重置密码的链接

请不要这么说,这是从我的手机写的,所以要注意打字错误

另外,您还询问了URL

就这样做吧:

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,})
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
url(r'unsubscribe/(?P<quit_hash>[\w\d]+)/$', 'quit_newsletter_or_somethin', name='quit_newsletter_or_somethin')

不要重新发明轮子。你应该用它来做这种东西。该库维护良好,正在积极开发。

@KlausD.,不,这是密码的一部分。此答案中描述的方法有以下问题:1使用后必须立即删除显式令牌,如果任何错误阻止了这种情况的发生,则可以重新使用密码重置令牌。2代币最好像密码一样,经过良好的散列和盐渍存储。3由于Python文档处于随机状态,因此不应出于安全目的使用它。注意警告!是的@AntonStrogonoff我同意,就像我说的,这个答案是用电话写的。但这只是一个总体思路,一种方法,可以使用并进一步发展。