Django 重置密码

2025-06-04

Django 重置密码

大家好!

除了登录和注销视图之外,Django 的身份验证应用还提供了允许用户在忘记密码时重置密码的视图。让我们继续看看如何在应用中添加此功能。


工作流程

1) 用户点击“忘记密码”链接 - 这将把他们带到一个页面,提示他们输入电子邮件地址。此视图将通过扩展内置的 来处理PasswordResetView

PasswordResetView- 此视图显示用户提交其电子邮件地址的表单 -> 检查数据库中是否存在具有所提供电子邮件地址的用户 -> 生成仅使用一次的密码重置链接 -> 最后将该链接发送到用户的电子邮件地址。

  • 注意- 如果提供的电子邮件地址未与任何用户关联,Django 不会抛出错误,但不会发送电子邮件,您可能想知道为什么,原因是为了“防止信息泄露给潜在的攻击者”。如果您不喜欢此功能,而希望让用户知道他们何时输入了正确的电子邮件地址,何时输入了错误的电子邮件地址,您可以随时从该类继承PasswordResetForm并对其进行一些自定义。

那么,为什么不直接使用这个视图,而是通过扩展它来创建我们自己的视图呢?

  • 下面让我们看一下代码并进行讨论。

视图.py

from django.urls import reverse_lazy
from django.contrib.auth.views import PasswordResetView
from django.contrib.messages.views import SuccessMessageMixin
class ResetPasswordView(SuccessMessageMixin, PasswordResetView):
    template_name = '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')
Enter fullscreen mode Exit fullscreen mode
  • template_name- 如果没有给出任何内容,django 默认使用 registry/password_reset_form.html 来呈现视图的相关模板,但由于我们的模板将位于我们的用户应用程序模板目录中,所以我们需要明确地告诉 django。
  • email_template_name- 用于生成带有重置密码链接的电子邮件正文的模板。
  • subject_template_name- 用于生成带有重置密码链接的电子邮件主题的模板。
  • success_message- 密码重置请求成功后将显示的消息。
  • success_url- 如果没有指定,Django 在密码请求成功后默认使用“password_reset_done”。但我认为直接将用户重定向到主页而不提供任何其他模板是合理的。

我们尚未设置我们的应用程序来发送电子邮件,但我们稍后会这样做。

-> 将此视图映射到我们主项目的 url 模式。

用户管理/urls.py

from django.urls import path
from users.views import ResetPasswordView


urlpatterns = [
    path('password-reset/', ResetPasswordView.as_view(), name='password_reset'),
]

Enter fullscreen mode Exit fullscreen mode

-> 现在让我们提供与视图相关的模板。在 users/templates/users/ 目录中创建以下模板。


密码重置.html

{% extends "users/base.html" %}
{% block content %}
    <div class="form-content my-3 p-3">
        <div class="container">
            <div class="row justify-content-center">
                <div class="col-lg-5">
                    <div class="card shadow-lg border-0 rounded-lg mt-0 mb-3">
                        <div class="card-header justify-content-center">
                            <div id="error_div"></div>
                          <h3 class="font-weight-light my-4 text-center">Forgot Password?</h3>
                        </div>
                        {% if form.errors %}
                            <div class="alert alert-danger alert-dismissible" role="alert">
                                <div id="form_errors">
                                    {% for key, value in form.errors.items %}
                                        <strong>{{ value }}</strong>
                                    {% endfor %}
                                </div>
                                <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                                    <span aria-hidden="true">&times;</span>
                                </button>
                            </div>
                        {% endif %}
                        <div class="card-body">
                            <form method="POST">
                                {% csrf_token %}
                                <div class="form-row">
                                    <div class="col-md-10 offset-md-1">
                                    <div class="form-group">
                                      <label class="small mb-1" for="id_email">Email</label>
                                        <input type="email" name="email"  class="form-control"
                                               autocomplete="email" maxlength="254" required id="id_email"
                                               placeholder="Enter email">
                                    </div>
                                </div>
                            </div>
                                <div class="form-row">
                                  <div class="col-md-10 offset-md-1">
                                    <div class="form-group mt-0 mb-1">
                                        <button type="submit" class="col-md-12 btn btn-dark">Submit
                                        </button>
                                    </div>
                                 </div>
                               </div>
                            </form>
                        </div>
                        <div class="card-footer text-center">
                            <div class="small">
                                <a href="{% url 'users-register' %}">Create A New Account</a><br><br>
                                <a href="{% url 'login' %}">Back To Login</a><br>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>

  </div>
{% endblock content %}
Enter fullscreen mode Exit fullscreen mode

密码重置电子邮件.html

{% autoescape off %}
  To initiate the password reset process for your {{ user.email }} Django Registration/Login App Account,
  click the link below:

  {{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

  If clicking the link above doesn't work, please copy and paste the URL in a new browser
  window instead.

  Sincerely,
  The Developer
{% endautoescape %}
Enter fullscreen mode Exit fullscreen mode

密码重置主题.txt

Django - Registration/Login App Password Reset
Enter fullscreen mode Exit fullscreen mode

-> 修改login.html中的死链接以指向password_reset

登录.html

<a href="{% url 'password_reset' %}"><i>Forgot Password?</i></a>
Enter fullscreen mode Exit fullscreen mode

2) 密码重置请求完成后,用户将被重定向到主页,并显示一条消息,提示用户查看邮箱地址。请注意,正如我之前提到的,即使请求重置密码的用户不存在,也会显示此消息。

3) 用户前往邮箱查看邮件。假设一切顺利,用户收到了设置密码的说明。邮件内容如下:

重置密码消息

4) 用户点击生成的链接,将获得一个输入新密码的表单。

重置表格

PasswordResetConfirmView是负责呈现此密码重置表单并验证令牌的视图,即令牌是否已过期,或者是否已被使用。

-> 将其映射PasswordResetConfirmView到我们主项目的 url 模式。

用户管理/urls.py

from django.urls import path
from django.contrib.auth import views as auth_views


urlpatterns = [
    path('password-reset-confirm/<uidb64>/<token>/',
         auth_views.PasswordResetConfirmView.as_view(template_name='users/password_reset_confirm.html'),
         name='password_reset_confirm'),
]
Enter fullscreen mode Exit fullscreen mode

URL 的参数是什么?

  • uidb64:以 base 64 编码的用户 ID。
  • token:密码恢复令牌,用于检查密码是否有效。

-> 现在,让我们为该视图提供模板。继续在我们的用户应用模板目录中创建password_reset_confirm.html 。

密码重置确认.html

{% extends "users/base.html" %}
{% block title %} Password Reset {% endblock title%}
{% block content %}
    <div class="form-content my-3 p-3">
        <div class="container">
            <div class="row justify-content-center">
                <div class="col-lg-5">
                    {% if validlink %}
                        <div class="card shadow-lg border-0 rounded-lg mt-0 mb-3">
                            <div class="card-header justify-content-center">
                              <h3 class="font-weight-light my-4 text-center">Reset Your Password</h3>
                            </div>
                            {% if form.errors %}
                                <div class="alert alert-danger alert-dismissible" role="alert">
                                    <div id="form_errors">
                                        {% for key, value in form.errors.items %}
                                            <strong>{{ value }}</strong>
                                        {% endfor %}
                                    </div>
                                    <button type="button" class="close" data-dismiss="alert" aria-label="Close">
                                        <span aria-hidden="true">&times;</span>
                                    </button>
                                </div>
                            {% endif %}

                            <div class="card-body">
                                <form method="POST">
                                    {% csrf_token %}
                                    <div class="form-row">
                                        <div class="col-md-10 offset-md-1">
                                            <div class="form-group">
                                                <label class="small mb-1" for="id_new_password1">New Password</label>
                                                <input type="password" name="new_password1" autocomplete="new-password"
                                                       class="form-control" required id="id_new_password1"
                                                       placeholder="Enter password"/>
                                                <span>
                                                </span>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="form-row">
                                        <div class="col-md-10 offset-md-1">
                                            <div class="form-group">
                                                <label class="small mb-1" for="id_new_password2">New Password Confirmation</label>
                                                <input type="password" name="new_password2" autocomplete="new-password"
                                                       required id="id_new_password2" class="form-control"
                                                       placeholder="Confirm password"/>
                                            </div>
                                        </div>
                                    </div>
                                    <div class="form-row">
                                        <div class="col-md-10 offset-md-1">
                                            <div class="form-group mt-0 mb-1">
                                                <button type="submit" class="col-md-12 btn btn-dark" id="reset">Reset Password</button>
                                            </div>
                                        </div>
                                    </div>
                                </form>
                            </div>
                        </div>
                    {% else %}
                    <div class="alert alert-warning">
                        The password reset link was invalid, possibly because it has already been used.
                        Please request a new password reset.
                    </div>
                    {% endif %}
                </div>
            </div>
        </div>
    </div>
{% endblock content %}
Enter fullscreen mode Exit fullscreen mode

5)如果密码重置成功,PasswordResetCompleteView将显示一个视图,让用户知道他/她的密码已成功更改。

重置完成

-> 将此视图映射到我们主项目的 url 模式。

用户管理/urls.py

from django.urls import path
from django.contrib.auth import views as auth_views


urlpatterns = [
    path('password-reset-complete/',
         auth_views.PasswordResetCompleteView.as_view(template_name='users/password_reset_complete.html'),
         name='password_reset_complete'),
]
Enter fullscreen mode Exit fullscreen mode

-> 提供 PasswordResetCompleteView 的模板

密码重置完成.html

{% extends "users/base.html" %}
{% block content %}
    <div class="container my-3 p-3">
        <div class="row justify-content-center">
            <div class="col-lg-5">
                <div class="card shadow-lg border-0 rounded-lg mt-0 mb-3">
                    <div class="alert alert-info">
                        Your password has been set. You may go ahead and <a href="{% url 'login' %}">Login Here</a>
                    </div>
                </div>
            </div>
        </div>
    </div>
{% endblock content %}
Enter fullscreen mode Exit fullscreen mode

在 Django 中设置发送电子邮件

我们已经配置了 django 让用户重置密码所需的一切,但我们实际上并没有向用户发送电子邮件,所以让我们继续这样做。

选项 1 - 建议您为您的 Google 帐户启用双重身份验证 (2FA),以便我们的应用能够发送电子邮件。请点击此链接进行设置。

选项 2 - 但如果您不想启用 2FA,那么只需转到此处并允许您的 Google 帐户使用安全性较低的应用程序。

更新: 自 2022 年 5 月 30 日起,“安全性较低的应用”设置将不再可用。点击此处了解原因。

好的,接下来转到settings.py并添加以下内容。

设置.py

# email configs
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_USE_TLS = True
EMAIL_PORT = 587
EMAIL_HOST_USER = str(os.getenv('EMAIL_USER'))
EMAIL_HOST_PASSWORD = str(os.getenv('EMAIL_PASSWORD'))
Enter fullscreen mode Exit fullscreen mode
  • EMAIL_BACKEND是电子邮件将通过的 SMTP 后端。
  • EMAIL_HOST是用于发送电子邮件的主机。
  • EMAIL_USE_TLS- 与 SMTP 服务器通信时是否使用 TLS(安全)连接。这用于显式 TLS 连接,通常在端口 587 上。
  • EMAIL_PORT- EMAIL_HOST 中定义的 SMTP 服务器使用的端口。
  • EMAIL_HOST_USEREMAIL_HOST_PASSWORD分别是 SMTP 服务器的用户名和密码。为了保证它们的安全,请将它们放在.env文件中,并在此处获取它们,就像我们在本系列上一篇介绍的那样。

它是否正常工作?

  • python manage.py runserver启动开发服务器并在终端中运行常用命令。
  • 访问 localhost 看看是否正常。遇到任何问题?欢迎随时咨询我。

感谢您抽出时间。您可以在GitHub上找到已完成的应用程序。我们下次再见,继续本系列的其他部分。

文章来源:https://dev.to/earthcomfy/django-reset-password-3k0l
PREV
Web Socket 简介
NEXT
5 个可添加到实用程序库的 JavaScript 函数