注:Python3,Django1.9
新开一个应用:user_ex,并在settings.py里注册
依赖项:django-simple-captcha (用pip)
settings.py
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
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
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
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
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
#用来发邮件的配置信息(这里用了新浪的) 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
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
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
{% 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
<html> <head> <title>密码重设</title> <style> .out{ width: 500px; height: 900px; margin: 0 auto; margin-top: 100px; } </style> </head> <body> <h1 style='text-align: center;'>用户 {{email}} 的密码重设</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
<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
<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
<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>
部分展示
来源:https://www.cnblogs.com/xikem/p/12201339.html