重置密码

2017-07-1016632 阅读40 评论

当用户不小心忘记了密码时,网站需要提供让用户找回账户密码的功能。在示例项目中,我们将发送一封含有重置用户密码链接的邮件到用户注册时的邮箱,用户点击收到的链接就可以重置他的密码,下面是具体做法。

发送邮件设置

Django 内置了非常方便的发送邮件的功能,不过需要在 settings.py 中做一些简单配置。生产环境下通常需要使用真实的邮件发送服务器,配置步骤会比较多一点。不过 Django 为开发环境下发送邮件提供了一些方便的 Backends 来模拟真实邮件的发送,例如直接发送邮件到终端()。在 settings.py 中加入以下设置:

settings.py

EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'

这样 Django 将把邮件发送到终端。

发送邮件设置好后,接下来的步骤和之前的登录,注册,修改密码等是完全类似的了,只需添加和修改相应模板即可。

编写重置密码模板

重置的视图函数默认渲染的模板名为 password_reset_form.html,因此首先在 registration/ 下新建一个 password_reset_form.html 文件,写入表单代码(几乎和登录页面一样),在此就不做过多解释了,具体请参考 Django 用户认证系统:登录 部分的说明。

registration/password_reset_form.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>重置密码</title>
    <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
    <style>
        .errorlist {
            color: red;
        }
    </style>
</head>
<body>
<div class="flex-center">
    <div class="container">
        <div class="flex-center">
            <div class="unit-1-2 unit-1-on-mobile">
                <h1><a href="{% url 'index' %}">Django Auth Example</a></h1>
                <h3>重置密码</h3>
                <form class="form" action="{% url 'password_reset' %}" method="post">
                    {% csrf_token %}
                    {{ form.non_field_errors }}
                    {% for field in form %}
                        {{ field.label_tag }}
                        {{ field }}
                        {{ field.errors }}
                        {% if field.help_text %}
                            <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
                        {% endif %}
                    {% endfor %}
                    <button type="submit" class="btn btn-primary btn-block">提交</button>
                </form>
            </div>
        </div>
    </div>
</div>
</body>
</html>

此外,修改一下重置密码按钮的超链接属性:

registration/login.html

...
<div class="flex-left top-gap text-small">
  <div class="unit-2-3"><span>没有账号?<a href="{% url 'users:register' %}">立即注册</a></span></div>
  <div class="unit-1-3 flex-right"><span><a href="{% url 'password_reset' %}">忘记密码?</a></span></div>
</div>
...

编写邮件发送成功页面模板

用户在重置密码页面输入注册时的邮箱后,Django 会把用户跳转到邮件发送成功页面,该页面渲染的模板为 password_reset_done.html,因此再添加一个密码修改成功页面的模板:

registration/password_reset_done.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>密码重置链接已经发送</title>
    <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
</head>
<body>
<div class="flex-center">
    <div class="container">
        <div>
            <h1 class="logo"><a href="{% url 'index' %}">Django Auth Example</a></h1>
            <h3>密码重置链接已经发送</h3>
            <p>
              如果您输入的邮件地址所对应的账户存在,设置密码的提示已经发送邮件给您,您将很快收到。
            </p>
            <p>
              如果你没有收到邮件, 请确保您所输入的地址是正确的, 并检查您的垃圾邮件文件夹.
            </p>
        </div>
    </div>
</div>
</body>
</html>

编写设置新密码页面模板

在接收到的重置密码邮件中有一个设置新密码的链接,点击该链接就会跳转到给账户设置新密码的页面,以便用户给已忘记密码的账户设置一个全新的密码。该页面渲染的模板为 password_reset_confirm.html,因此再添加一个设置新密码页面的模板。首先在 registration/ 下新建一个 password_reset_confirm.html 文件,写入表单代码(几乎和登录页面一样),在此就不做过多解释了,具体请参考 Django 用户认证系统:登录 部分的说明。

registration/password_reset_confirm.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>设置新密码</title>
    <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
    <style>
        .errorlist {
            color: red;
        }
    </style>
</head>
<body>
<div class="flex-center">
    <div class="container">
        <div class="flex-center">
            <div class="unit-1-2 unit-1-on-mobile">
                <h1><a href="{% url 'index' %}">Django Auth Example</a></h1>
                <h3>设置新密码</h3>
                <form class="form" method="post">
                    {% csrf_token %}
                    {{ form.non_field_errors }}
                    {% for field in form %}
                        {{ field.label_tag }}
                        {{ field }}
                        {{ field.errors }}
                        {% if field.help_text %}
                            <p class="help text-small text-muted">{{ field.help_text|safe }}</p>
                        {% endif %}
                    {% endfor %}
                    <button type="submit" class="btn btn-primary btn-block">提交</button>
                </form>
            </div>
        </div>
    </div>
</div>
</body>
</html>

编写设置新密码成功页面模板

用户在设置新密码页面输入新密码后,Django 会把用户跳转到设置新密码成功页面,该页面渲染的模板为 password_reset_complete.html,因此再添加一个设置新密码成功页面的模板:

registration/password_reset_complete.html

<!DOCTYPE html>
<html lang="zh-cn">
<head>
    <meta charset="utf-8">
    <meta http-equiv="x-ua-compatible" content="ie=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
    <title>新密码设置成功</title>
    <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
</head>
<body>
<div class="flex-center">
    <div class="container">
        <div>
            <h1 class="logo"><a href="{% url 'index' %}">Django Auth Example</a></h1>
            <h3>新密码设置成功</h3>
            <p>
                你的口令己经设置。现在你可以继续进行登录。
            </p>
        </div>
    </div>
</div>
</body>
</html>

测试整个流程

重置密码的流程略微复杂一点,其整个过程为:用户输入注册时邮箱,跳转到发送成功页面 → 系统发送激活链接邮件到用户邮箱 → 用户进入邮箱,点击激活链接跳转到设置新密码页面 → 用户设置新密码,跳转到设置成功页面。下面就来看看整个过程。

输入注册时邮箱

在登录页面点击找回密码的按钮,跳转到输入注册邮箱页面:

输入注册时邮箱

邮件发送成功

输入正确的邮箱地址后,系统将发送重置密码的邮件到终端:

重置密码邮件发送成功

在终端可以接收到如下的邮件内容:

你收到这封邮件是因为你请求重置你在网站 127.0.0.1:8000上的用户账户密码。

请访问该页面并选择一个新密码:

http://127.0.0.1:8000/users/reset/NA/4n8-64ab7ff92254d18c6b15/

你的用户名,如果已忘记的话: zmrenwu

感谢使用我们的站点!

127.0.0.1:8000 团队

点击内容中的链接,将跳转到设置新密码的页面。

设置新密码

在设置新密码的页面输入需要设置的新密码:

设置新密码

新密码设置成功

点击提交后将跳转到新密码设置成功页面:

新密码设置成功

现在便可以用新设置的密码登录了。

总结

本教程的示例项目代码位于 GitHub:Django Auth Example

如果遇到问题,请通过下面的方式寻求帮助。

更多 Django 相关教程,请访问我的个人博客:追梦人物的博客

-- EOF --

40 评论
登录后回复
用户7275707198
2019-08-08 17:20:13

博主  由出现一个问题:由于目标计算机积极拒绝,无法连接

回复
LebronJames-ymq 用户7275707198
2020-09-24 16:54:42

关闭你的代理

回复
hk03024996
2019-05-30 22:29:51

博主您好,就是这课重置密码选项是否有客户端能完成的方法,请博主给点思路谢谢。目前的方式是需要服务器端请访问。该页面并选择一个新密码:http://127.0.0.1:8000/users/reset/NA/4n8-64ab7ff92254d18c6b15/来重置。谢谢博主。

回复
Leo
2019-03-20 16:37:49

我用新浪邮箱的smtp,在本地测试可以发送修改密码的邮件,可是放到服务器上就不行。报502错误。有人知道什么回事么

回复
BigOrange128 Leo
2019-04-20 16:19:22

端口被屏蔽了,换成465即可。

回复
BigOrange128 BigOrange128
2019-04-20 16:19:45

还要改协议

EMAIL_USE_SSL = True

回复
github-abc123
2019-03-10 04:21:58

为什么重置密码的邮件会发两遍,打印结果如下:

[10/Mar/2019 02:35:57] "GET /users/password_reset/ HTTP/1.1" 200 1371
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Subject: =?utf-8?b?6YeN572uIDEyNy4wLjAuMTo4MDAwIOeahOWvhueggQ==?=
From: webmaster@localhost
To: wst.521@163.com
Date: Sat, 09 Mar 2019 18:36:00 -0000
Message-ID: <155215656087.10266.2474610881351178491@lenovowst-PC>


你收到这封邮件是因为你请求重置你在网站 127.0.0.1:8000上的用户账户密码。

请访问该页面并选择一个新密码:

http://127.0.0.1:8000/users/reset/Mg/54i-a6f8a9bd65a9c1c7673c/

你的用户名,如果已忘记的话: wst

感谢使用我们的站点!

127.0.0.1:8000 团队



-------------------------------------------------------------------------------
[10/Mar/2019 02:36:00] "POST /users/password_reset/ HTTP/1.1" 302 0
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: 8bit
Subject: =?utf-8?b?6YeN572uIDEyNy4wLjAuMTo4MDAwIOeahOWvhueggQ==?=
From: webmaster@localhost
To: wst.521@163.com
Date: Sat, 09 Mar 2019 18:36:00 -0000
Message-ID: <155215656087.10266.3376107342476971813@lenovowst-PC>


你收到这封邮件是因为你请求重置你在网站 127.0.0.1:8000上的用户账户密码。

请访问该页面并选择一个新密码:

http://127.0.0.1:8000/users/reset/Mw/54i-30874a67d9762a85d28d/

你的用户名,如果已忘记的话: admin

感谢使用我们的站点!

127.0.0.1:8000 团队
回复
github-abc123 github-abc123
2019-03-10 10:52:05

后来发现原因:用同一个邮箱注册了多个账号,为了防止出现这种情况,user的models.py改为如下(加了email唯一):

users/models.py

from django.db import models
from django.contrib.auth.models import AbstractUser


class User(AbstractUser):
    nickname = models.CharField(max_length=50, blank=True)
    email = models.EmailField(unique=True)

    class Meta(AbstractUser.Meta):
        pass
回复
socker111
2019-03-06 14:30:40

这里的话 我遇到了一个小问题跟大家分享一下,如果你要用QQ邮箱来进行重置密码,首先需要改成SMTP,如:

EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend' 然后在QQ邮箱里面开启POP3/SMTP服务和IMAP/SMTP服务(开启步骤:进入QQ邮箱,点击设置,弹出邮箱设置,点击账号,下拉找到开启服务),然后在settings配置中添加如下配置:EMAIL_HOST = 'smtp.qq.com' EMAIL_PORT = 25 EMAIL_HOST_USER ='你的QQ号@qq.com'EMAIL_HOST_PASSWORD = '你的QQ邮箱中生成的授权码' EMAIL_USE_TLS = True EMAIL_FROM ='你的QQ号@qq.com' DEFAULT_FROM_EMAIL = '你的QQ号@qq.com' 这样之后,我才能正确的收到邮件,希望对大家有帮助!

回复
somenzz
2018-06-01 16:06:06

请问

  1. 如何确保用户注册时使用的邮箱是唯一的呢,就像检查用户名一样?
  2. 注册时如何填写用中文姓名呢?
回复
追梦人物 somenzz
2018-06-04 18:04:11

用户名内置支持中文姓

确保邮箱唯一的话可以在表单中添加 clean_email 方法验证表单,如果邮箱已被注册就验证不通过,提醒用户。

回复
SamK6517433923 somenzz
2019-02-27 14:10:55

User 模型中 email 字段需要设置 unique=True , 就可以实现用户注册时使用的邮箱是唯一的。

回复
郭效杨
2018-03-01 21:28:55

请教博主,我配置好了邮箱,那么如何更改设置让邮件发送到我的163邮箱呢

回复
追梦人物 郭效杨
2018-04-16 11:53:17

把 backend 改一下,改成 SMTP 的 backend 就可以了。

回复
Ivan
2018-02-19 14:47:18

博主,请问一下,为什么我的终端接受不到邮件?

回复
Ivan Ivan
2018-02-19 15:13:01

发现问题了,邮箱名和用户邮箱没对应起来=。=!

回复
dragon
2017-12-12 20:48:44

博主你好,为什么我按那个后台发送的链接后他提示是Example Domain不允许修改密码,正式的修改密码形式是什么??

回复
Symbianl
2017-10-23 10:22:21

请问下博主,终端内容怎么修改?

回复
追梦人物 Symbianl
2017-10-23 12:18:03

同样的思路,覆盖django默认的模板内容即可。

回复
追梦人物
2017-09-02 19:27:20

需要配置 SMTP backend。百度搜 django 如何发送邮件有大量教程,对着设置就可以了。

回复
韦子扬不想穿秋裤
2017-09-01 22:08:40

您好,可以问一下,本篇怎么把发送到终端的邮件改成真实的邮件呢?应该如何配置?

回复
mozhemeng
2017-08-30 10:05:32

博主,为什么 编写设置新密码页面模板 的表单没有action属性,但也能成功提交呢,他是提交到哪里呢

回复
追梦人物 mozhemeng
2017-08-30 12:43:07

如果省略 action,则默认提交到当前页面的 url,所以也能提交成功。

回复
亲爱的-阿涛
2017-08-17 16:42:55

设置新密码页面没有表单

回复
追梦人物 亲爱的-阿涛
2017-08-17 20:53:25

可能是你的模板写错了。或者没有传递表单 form 给模板

回复
dgsudfjk
2017-08-08 20:42:28

为什么只有login可以使用自定义模板,其他的都是admin后台呢,都放在registration文件夹下了

回复
追梦人物 dgsudfjk
2017-08-08 20:50:49

很可能是模板名或者路径放置有问题,对比一下我给出的 github 项目,看看模板的名称和放置的路径。

回复
dgsudfjk 追梦人物
2017-08-08 20:54:27

嗯,的确是这个原因,registration要在项目根目录下的templates里才行,在app里的templates就不行

回复
dgsudfjk 追梦人物
2017-08-08 20:56:23

但是好奇怪,login就没这个问题

回复
追梦人物 dgsudfjk
2017-08-08 22:45:18

login 是经由 next 或者 LOGIN_REDIRECT 跳转的。

回复
liuxinglan13
2017-08-01 13:59:21

方式

回复
DawnOct
2017-08-01 09:25:50

博主早上好, 请问可以在django 后台的基础上,自定义样式么?

回复
追梦人物 DawnOct
2017-08-02 10:12:59

可以的,django 的官方 tutorial 中有基础的示例。

回复
kuaidanian
2017-07-17 16:13:42

能转载博主的文章吗?

回复
追梦人物 kuaidanian
2017-07-19 12:40:35

可以的

回复
shanyongxu
2017-07-14 17:09:29

博主大大,最近在研究什么新技术啊?可以分享一下吗?

回复
追梦人物 shanyongxu
2017-07-19 12:48:11

最近在读 django 源码,写了一些笔记,到时候会发出来,有兴趣的可以看看咯。

回复
shanyongxu 追梦人物
2017-07-20 09:03:00

这是必然要想博主学习的.

回复
Ehco
2017-07-11 19:26:37

很不错,谢谢了,希望能添加在服务器上部署的相关教程

回复
追梦人物 Ehco
2017-07-11 21:08:46

我对服务器方面的东西也不是很熟,希望有经验的朋友可以多多分享。

回复