Django网站用户邮箱验证找回密码

注:Python3,Django1.9

新开一个应用:user_ex,并在settings.py里注册

依赖项:django-simple-captcha (用pip)

settings.py

1
2
3
4
5
6
7
8
9
10
11
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'......',
'user_ex',
'captcha',
]

主路由urls.py包含应用user_ex的路由和依赖项captcha的路由

urls.py

1
2
3
4
5
6
7
from django.conf.urls import url
from django.conf.urls import include

urlpatterns = [
url(r'^user_ex/',include('user_ex.urls')),
url(r'^captcha/',include('captcha.urls')),
]

应用user_ex对应路由配置

user_ex.urls.py

1
2
3
4
5
6
7
8
from django.conf.urls import url
from . import views

urlpatterns = [
url(r'^identify',views.identify,name='identify'),
url(r'^reset/(.*)/(.*)$',views.reset_password),
url(r'^modify/',views.modify,name="modify"),
]

后台数据库模型定义

user_ex.models

1
2
3
4
5
6
7
8
9
10
11
from django.db import models
from django.utils import timezone


# Create your models here.
class EmailVerifyRecord(models.Model):
code = models.CharField("动态生成的更改信息的链接后缀",max_length=25)
email = models.CharField("邮箱",max_length=30)
valid_time = models.DateTimeField("验证建立时间",null=False,default=timezone.now) #验证码的建立时间,由此确定有效时间段
class Meta:
verbose_name_plural = '给邮箱发链接(忘记密码)所用信息'

表单提交对应的格式定义

user_ex.forms

1
2
3
4
5
6
7
8
9
10
from django import forms
from captcha.fields import CaptchaField

class IdentifyForm(forms.Form):
email=forms.EmailField(required=True)
captcha=CaptchaField(error_messages={'invalid':'验证码错误'})

class ResetForm(forms.Form):
newpwd1=forms.CharField(required=True,min_length=6,error_messages={'required': '密码不能为空.', 'min_length': "至少6位"})
newpwd2 = forms.CharField(required=True, min_length=6, error_messages={'required': '密码不能为空.', 'min_length': "至少6位"})

配置EMAil_FORM(还需要注册邮箱,登录后开通邮件服务器)

settings.py

1
2
3
4
5
6
7
#用来发邮件的配置信息(这里用了新浪的)
EMAIL_HOST='smtp.sina.com'
EMAIL_PORT=587
EMAIL_HOST_USER='*******@sina.com'
EMAIL_HOST_PASSWORD='*********'
EMAIL_USE_TLS=True
EMAIL_FROM='*******@sina.com' #同上面,你的发送邮件的邮箱

后端响应配套的工具集

user_ex.utils

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
from random import Random
from .models import EmailVerifyRecord
from django.core.mail import send_mail
from nuckaggle.settings import EMAIL_FROM


def random_str(randomlength=8): # 获得链接后面的加密参数
str=''
chars='AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789'
length=len(chars)-1
random=Random()
for i in range(randomlength):
str+=chars[random.randint(0,length)]
return str

def send_forget_email(email):
email_record=EmailVerifyRecord()
code=random_str(16)
email_record.code=code
email_record.email=email
email_record.save()

email_title = '*********网站密码重置链接'
email_body = '(如非本人操作,请忽略)请点击下面的链接重置你的密码(有效时间:10分钟):http://**主机域名**/user_ex/reset/{0}/{1}'.format(email,code)

send_status = send_mail(email_title, email_body, EMAIL_FROM, [email])
if send_status:
return 1
else:
return 0

配套的工具模型格式依赖等写好,可以写后端的响应了

user_ex的后端响应

user_ex.views

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
from django.http import HttpResponseRedirect
from django.shortcuts import render
from .forms import IdentifyForm,ResetForm
from .utils import send_forget_email
from django.contrib.auth.models import User
from .models import EmailVerifyRecord
from django.utils import timezone

# Create your views here.
def home(request):
return render(request,'account/error.html')

def identify(request):
context = {}
identify_from = IdentifyForm()
if request.method == 'POST':
form = IdentifyForm(request.POST)
if form.is_valid():
email=request.POST.get('email','')
us = User.objects.filter(email = email)
if us:
is_send = send_forget_email(email)
if is_send:
return render(request,'user_ex/send_successful.html')
else:
return render(request,'user_ex/send_fail.html')
else:
context["identify_from"] = identify_from
context["statu"] = 1
context["error"] = "此邮箱未注册"
return render(request,'user_ex/identify.html',context)
else:
context["identify_from"] = identify_from
context["statu"] = 1
context["error"] = "验证码错误"
return render(request,'user_ex/identify.html',context)
else:
context["identify_from"] = identify_from
context["statu"] = 0
return render(request,'user_ex/identify.html',context)

def reset_password(request,email,active_code):
context = {}
record=EmailVerifyRecord.objects.filter(email = email,code = active_code)
if record:
i = record[len(record)-1] #虽然概率极低,有多个的话,取最新的那个(最可能有效)
create = i.valid_time
td = timezone.now() - create #执行这个步骤时now一定比create晚
if td.seconds//60 > 9 and td.days < 1: #链接10分钟内有效
context['type'] = '链接超时'
context['message'] = '此链接已经超时失效,请重新获取'
referer = request.META.get('HTTP_REFERER')
context["redirect_to"] = referer
return render(request,'account/error.html',context)
email=i.email
user = User.objects.get(email = email)
return render(request,'user_ex/pass_reset.html',{'email':email,'username':user.username})
return HttpResponseRedirect('/')

def modify(request):
reset_form=ResetForm(request.POST)
if reset_form.is_valid():
pwd1=request.POST.get('newpwd1','')
pwd2=request.POST.get('newpwd2','')
email=request.POST.get('email','')
if pwd1!=pwd2:
return render(request,'user_ex/pass_reset.html',{'msg':'密码不一致!','statu':1,'error':"密码不合规,此页面失效,请重新使用邮箱链接"})
else:
user=User.objects.get(email=email)
user.set_password(pwd2)
user.save()
return render(request,'user_ex/reset_success.html')
else:
email=request.POST.get('email','')
return render(request,'user_ex/pass_reset.html',{'msg':reset_form.errors,'statu':1,'error':"密码不合规,此页面失效,请重新使用邮箱链接"})

注:if td.seconds//60 > 9 and td.days < 1:

链接10分钟内有效(仔细看下python的timedelta类,只有两个属性seconds和days)

页面模板

acount应用的一个简单的错误页面error.html(写在其他地方也行)

identify.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
{% load static %}
<html>
<head>
<title>验证</title>
<style>
.cap{
display: inline-block;
width: 280px;
height: 36px;
}
.cap img{
float: right;
}
</style>
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
<script>
$(function(){
$('.captcha').css({
'cursor': 'pointer'
});
/*# ajax 刷新*/
$('.captcha').click(function(){
console.log('click');
$.getJSON("/captcha/refresh/",function(result){
$('.captcha').attr('src', result['image_url']);
$('#id_captcha_0').val(result['key'])
});
});
})
</script>
</head>
<body>
<h2>邮箱验证修改密码</h2>
<div class="modal fade" id="register" tabindex="-1" role="dialog">
<form action="" enctype="multipart/form-data" method="post">
<p><div style="display: inline-block;width:100px;text-align: center"><b >邮箱:</b></div>
<div class="cap">{{ identify_from.email }}</div>
</p>

<P><div style="display: inline-block;width:100px;text-align: center"><b >验证码:</b></div>
<!--验证码start-->
<div class="cap">{{ identify_from.captcha }}</div>
<!--验证码end-->
</P>
{% csrf_token %}
<div>
<label>向您的邮箱发送修改密码的链接</label>
<input type="submit" value="发送">
</div>
</form>
</div>
<script>
a={{ statu }};
if (a==1)
{


window.alert('\n\n {{ error }}\n\n');
}
</script>
</body>
</html>

pass_reset.html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
<html>
<head>
<title>密码重设</title>
<style>
.out{
width: 500px;
height: 900px;
margin: 0 auto;
margin-top: 100px;
}
</style>
</head>
<body>
<h1 style='text-align: center;'>用户&nbsp{{email}}&nbsp的密码重设</h1>
<h2 style='text-align: center;'>您的用户名为:{{username}}</h2>
<div class="out">
<h1>可以重新设置一个好记的新密码啦!</h1>
<form method="post" action="{% url 'modify' %}">
<P><span>新密码:</span><input type="password" name="newpwd1" placeholder="至少6位"></P>
<P><span>确认新密码:</span><input type="password" name="newpwd2" placeholder="至少6位"></P>
{% csrf_token %}
<input type="hidden" name="email" value="{{ email }}">
<p><input type="submit" value="确认"></p>
</form>
<h1>{{ msg }}</h1>
<script>
a={{ statu }};
if (a==1)
{


window.alert('\n\n {{ error }}\n\n');
}
</script>
</div>
</body>
</html>

reset_success.html

1
2
3
4
5
6
7
8
9
10
<html>
<head>
<title>successful</title>
</head>
<body>
<h1 style='text-align: center;font-size: %222'>successful<br>
<h2 style='text-align: center'>您的密码已经重置,请牢牢记住新密码</h2>
</h1>
</body>
</html>

send_fail.html

1
2
3
4
5
6
7
8
9
10
<html>
<head>
<title>fail</title>
</head>
<body>
<h1 style='text-align: center;font-size: %222'>fail<br>
<h2 style='text-align: center'>由于网络或其他原因,未成功向邮箱发送密码重置链接,请重试</h2>
</h1>
</body>
</html>

send_successful.html

1
2
3
4
5
6
7
8
9
10
<html>
<head>
<title>successful</title>
</head>
<body>
<h1 style='text-align: center;font-size: %222'>successful<br>
<h2 style='text-align: center'>已经向您的邮箱发送邮件成功,请注意查收(不在收件箱就一定在垃圾箱)</h2>
</h1>
</body>
</html>

部分展示







Django网站用户邮箱验证找回密码
https://blog.wangxk.cc/2019/05/01/Django网站用户邮箱验证找回密码/
作者
Mike
发布于
2019年5月1日
许可协议