1.邮箱验证环境搭建
基本的项目搭建方式还是可以参考专栏中前几篇文章
model
创建模型,并迁移数据库(sqlite)
from django.db import models
# Create your models here.
class User(models.Model):
username = models.CharField(max_length=30)
password = models.CharField(max_length=100)
templates
在子应用下创建templates/code_app/register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<table>
<tr>
<td>用户名:</td>
<td><input type="text" id="username" name="username" placeholder="请输入您的邮箱号"></td>
</tr>
<tr>
<td>验证码:</td>
<td>
<input type="text" name="vcode" placeholder="请输入您的邮箱验证码">
</td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password" placeholder="请输入您的密码"></td>
</tr>
<tr>
<td>密码确认:</td>
<td><input type="password" name="password2" placeholder="请确认您的密码"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="注册">
</td>
</tr>
</table>
</form>
</body>
</html>
views
from django.shortcuts import render
# Create your views here.
def register_html(request):
return render(request,'code_app/register.html')
urls
from django.contrib import admin
from django.urls import path, include
from code_app import views
app_name = 'code_app'
urlpatterns = [
path('register_html/',views.register_html)
]
2. 邮箱验证smtp发送邮件
在根目录下创建common文件夹
生成随机码
创建string_help.py
import random
def gen_vcode(length=4):
# 返回一个随机字符串,生成4位验证码
return ''.join(random.choices('0123456789', k=length))
发送邮件
创建mail_helper.py
from string_help import gen_vcode
from email.header import Header
from email.mime.text import MIMEText
from email.utils import parseaddr,formataddr
import smtplib
# 格式化编码,以防乱码
def _format_addr(s):
name, addr = parseaddr(s)
return formataddr((Header(name, 'utf-8').encode(), addr))
# 构建发送邮件对象
def gen_vcode_msg(vcode, from_addr, to_addr):
"""
vcode: 发送的验证码
from_addr: 发送方邮箱
to_addr: 接收方邮箱
return: 返回含有发送验证码的MIMEText对象
"""
text = f'您好,欢迎注册测试网。您的验证码是:{vcode},有效期为20分钟, 请立即验证。'
msg = MIMEText(text,'plain', 'utf-8')
msg['From'] = _format_addr('测试网<%s>' %from_addr)
msg['To'] = _format_addr('新用户<%s>' % to_addr)
msg['Subject'] = Header('测试网注册验证码','utf-8').encode()
return msg
def send_vcode(smtp_server, from_addr,password, to_addr):
"""
smtp_server: 当前使用smtp(qq邮箱)服务器
from_addr: 发送方邮箱
password: 发送方邮箱密码(授权码)
to_addr: 接收方邮箱
"""
# 构建一个 smtp 对象
server = smtplib.SMTP(smtp_server, 25)
# 设置一个调试级别(上线可以关闭)
server.set_debuglevel(1)
# 登录
server.login(from_addr, password)
# 构造要发送邮件的内容
vcode = gen_vcode() # 验证码
msg = gen_vcode_msg(vcode, from_addr, to_addr) # 邮件对象
# 发送邮件
server.sendmail(from_addr, [to_addr],msg.as_string())
server.quit() # 退出
return vcode
if __name__ == '__main__':
from_addr = '1339559006@qq.com'
to_addr = '1339559006@qq.com'
password = 'bqruoshflxyijabe'
smtp_server = 'smtp.qq.com'
code = send_vcode(smtp_server,from_addr, password, to_addr)
print('发送的验证码:',code)
3.在模板中添加发送邮件
创建文件夹存放jquery
views
调用发送邮件函数(在第二点中)
from django.shortcuts import render
from common import mail_help,string_help
from django.conf import settings
from django.http import JsonResponse
# Create your views here.
def register_html(request):
return render(request,'code_app/register.html')
# 发送验证码
def send_mail_vcode(request):
username = request.POST.get('username')
code = mail_help.send_vcode(settings.MAIL_SMTP_SERVER, settings.MAIL_FROM_ADDR,settings.MAIL_PASSWORD, username)
resp = {'msg':'验证码已发送,请查阅'}
return JsonResponse(resp)
修改templates
使用jquery调用视图函数,绑定到发送邮件按钮中
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
<script src="{% static 'code_app/js/jquery-3.6.1.min.js' %}"></script>
<!-- <script src="code_app\static\code_app\js\jquery-3.6.1.min.js"></script> -->
<script>
// 由于django会进行csrf验证,如果不添加这个代码,那么所有的ajax的post请求,都会验证失败
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ scrf_token }}' },
});
function send_mail_vcode() {
// 获取用户邮箱
var username = $('#username').val()
// 提交ajax的请求
$.ajax({
url:"{% url 'code_app:send_mail_vcode' %}",
type:'POST',
data: {'username': username},
success:function(data){
alert(data['msg']);
}
})
}
</script>
</head>
<body>
<form action="" method="post">
{% csrf_token %}
<table>
<tr>
<td>用户名:</td>
<td><input type="text" id="username" name="username" placeholder="请输入您的邮箱号"></td>
</tr>
<tr>
<td>验证码:</td>
<td>
<input type="text" name="vcode" placeholder="请输入您的邮箱验证码">
<input type="button" value="发送验证码" onclick="return send_mail_vcode();">
</td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password" placeholder="请输入您的密码"></td>
</tr>
<tr>
<td>密码确认:</td>
<td><input type="password" name="password2" placeholder="请确认您的密码"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="注册">
</td>
</tr>
</table>
</form>
</body>
</html>
配置settings
- 注释csrf中间件,否则报错Forbidden (CSRF token missing or incorrect.)
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
# 'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
- 添加配置
STATIC_URL = '/static/'
STATICFILES_DIRS = [
os.path.join(BASE_DIR, 'static')
]
# Default primary key field type
# https://docs.djangoproject.com/en/3.2/ref/settings/#default-auto-field
DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
# 邮箱配置
MAIL_FROM_ADDR = '1339559006@qq.com'
MAIL_PASSWORD = 'bqruoshflxyijabe'
MAIL_SMTP_SERVER = 'smtp.qq.com'
4. 邮箱验证验证码输入是否正确
4.1 邮箱验证验证码之保存验证码在session
可以保存验证码在session中,也可以参考专栏的Tornado项目,保存在redis中。
完善views代码
# 发送验证码
def send_mail_vcode(request):
username = request.POST.get('username')
# 获取当前时间
now_time = time.time()
# 获取上次发送邮件的时间
mail_code_time = request.session.get('mail_code_time')
if mail_code_time and now_time < mail_code_time + settings.MAIL_INTERVAL:
resp = {'msg':f'{settings.MAIL_INTERVAL}秒内,不能重复发送邮件'}
else:
code = mail_help.send_vcode(settings.MAIL_SMTP_SERVER, settings.MAIL_FROM_ADDR,settings.MAIL_PASSWORD, username)
resp = {'msg':'验证码已发送,请查阅'}
# 存储验证码
request.session['mail_code'] = code
request.session['mail'] = username
# 存储发送邮件时间
request.session['mail_code_time'] = time.time()
return JsonResponse(resp)
settings配置
# 邮箱配置
MAIL_INTERVAL = 20 # 不可以重复发送的时间
4.2 邮箱验证验证码之验证验证码是否正确
views视图函数
def validate_mail_vcode(request):
# 获取输入的验证码和邮箱
username = request.POST.get('username')
vcode = request.POST.get('vcode')
# 从session中获取邮箱和验证码
session_username = request.session.get('mail')
session_code = request.session.get('mail_code')
# 判断发送用户是否一致
if session_username and session_username == username:
# 判断验证码是否失效
now_time = time.time()
# 获取发送验证码时间
session_code_time = request.session.get('mail_code_time')
if session_code_time and now_time <= session_code_time + settings.VCODE_EXPIRE:
# 验证验证码输入
if session_code and session_code == vcode:
resp = {'ok':1,'msg':'验证码正确'}
else:
resp = {'ok':0,'msg':'验证码输入不正确'}
else:
resp = {'ok':0,'msg':'验证码失效,请重新获取'}
else:
resp = {'ok':0,'msg':'该账户没有获取验证码'}
return JsonResponse(resp)
templates
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>用户注册</title>
<script src="{% static 'code_app/js/jquery-3.6.1.min.js' %}"></script>
<!-- <script src="code_app\static\code_app\js\jquery-3.6.1.min.js"></script> -->
<script>
// 由于django会进行csrf验证,如果不添加这个代码,那么所有的ajax的post请求,都会验证失败
$.ajaxSetup({
data: {csrfmiddlewaretoken: '{{ scrf_token }}' },
});
function send_mail_vcode() {
// 获取用户邮箱
var username = $('#username').val()
// 提交ajax的请求
$.ajax({
url:"{% url 'code_app:send_mail_vcode' %}",
type:'POST',
data: {'username': username},
success:function(data){
alert(data['msg']);
}
})
}
// 验证输入验证码是否正确
function validate_vcode(){
// 获取输入的邮箱
var username = $('#username').val();
// 在验证码输入框中添加id获取值
var vcode = $('#vcode').val();
// 发送异步请求进行验证
$.ajax({
// 调用视图函数
url:"{%url 'code_app:validate_mail_vcode'%}",
// 请求方式
type:'POST',
// 传递的数据
data:{
'vcode':vcode,
'username':username
},
success:function(data){
if(!data['ok']){
alert(data['msg']);
return false;
}else{
alert(data['msg']);
return true;
}
}
});
// 若无获取到邮箱和验证码输入框存在内容
return false;
}
</script>
</head>
<body>
<form action="" method="post" onsubmit="validate_vcode();">
{% csrf_token %}
<table>
<tr>
<td>用户名:</td>
<td><input type="text" id="username" name="username" placeholder="请输入您的邮箱号"></td>
</tr>
<tr>
<td>验证码:</td>
<td>
<input type="text" id='vcode' name="vcode" placeholder="请输入您的邮箱验证码">
<input type="button" value="发送验证码" onclick="return send_mail_vcode();">
</td>
</tr>
<tr>
<td>密码:</td>
<td><input type="password" name="password" placeholder="请输入您的密码"></td>
</tr>
<tr>
<td>密码确认:</td>
<td><input type="password" name="password2" placeholder="请确认您的密码"></td>
</tr>
<tr>
<td colspan="2">
<input type="submit" value="注册">
</td>
</tr>
</table>
</form>
</body>
</html>
settings配置
VCODE_EXPIRE = 60*2 # 验证码有效时间
效果展示
5. 邮箱验证通过完成注册
templates完善注册请求
views视图函数
from django.shortcuts import render
from common import mail_help,string_help
from django.conf import settings
from django.http import JsonResponse,HttpResponse
import time
from code_app.models import *
def register(request):
# 获取表单中的数据
username = request.POST.get('username')
password = request.POST.get('password')
# 添加到数据库
user = User.objects.create(
username = username,
password = password
)
return HttpResponse(f'注册成功,{user.id}')
效果展示
6.短信验证
这里的短信验证将会和邮箱验证放在一起,可以按需获取代码
6.1 使用云片网发送短信验证
- 云片网网址:https://www.yunpian.com/
- 注册账号
- 新账户赠送0.5元,可以不用充值测试
- 接入短信
- 进行个人实名认证
- 实名信息审核通过后,设置签名 和 短信模板
- 需要获取两个信息:
- apikey
- 短信模板
- 实现接口,查看api文档,选择使用单条发送接口 https://www.yunpian.com/official/document/sms/zh_CN/domestic_single_send
在common下创建yunpian.py发送短信请求
import json
import random
from urllib import parse, request
def send_sms_single(apikey, text, mobile):
"""
通用接口发短信
apikey:云片网的apikey
text:短信发送内容
mobile:接收方手机号
return :json_data
"""
url = 'https://sms.yunpian.com/v2/sms/single_send.json'
headers = {
"Content-type": "application/x-www-form-urlencoded;charset=utf-8;",
"Accept":"application/json;charset=utf-8;"
}
data = {
'apikey': apikey,
'text': text,
'mobile': mobile
}
# apikey= &text= &mobile=
data = parse.urlencode(data).encode('utf-8')
# 生成有个request对象
req = request.Request(url,headers=headers, data=data)
# 执行发送 返回字符串
content = request.urlopen(req).read().decode()
# 将字符串转化成json
json_data = json.loads(content)
return json_data
def send_sms(apikey, template, mobile):
'''
发送短信
apikey:云片网账号 apikey
template: 云片网审核通过的模板内容
mobile:接收方手机号
return: True,vcode 是否发送成功,验证码
'''
# 生成随机验证码
vcode = ''.join(random.choices('0123456789', k=4))
# 生成短信内容
text = template.format(vcode)
# 调用发送短信方法
json_data = send_sms_single(apikey, text, mobile)
print('云片网结果:', json_data)
if json_data['code'] == 0:
return True, vcode
else:
return False, vcode
if __name__ == '__main__':
apikey = 'b35ccda2ee775c10'
template = '【一天拓客】您的验证码是{}。如非本人操作,请忽略本短信。'
b, vcode = send_sms(apikey, template, '181')
print(vcode)
6.2在模板中实验短信验证
settings
# 配置发送短信
YUNPIAN_APIKEY = '5c10'
YUNPIAN_TEMPLATE = '【一天拓客】您的验证码是{}。如非本人操作,请忽略本短信。' # 规定的模板
views视图
from django.shortcuts import render
from common import mail_help,string_help, yunpian
from django.conf import settings
from django.http import JsonResponse,HttpResponse
import time
from code_app.models import *
# Create your views here.
def register_html(request):
return render(request,'code_app/register.html')
# 发送验证码
def send_vcode(request):
username = request.POST.get('username')
# 获取当前时间
now_time = time.time()
# 获取上次发送邮件的时间
mail_code_time = request.session.get('mail_code_time')
if mail_code_time and now_time < mail_code_time + settings.MAIL_INTERVAL:
resp = {'msg':f'{settings.MAIL_INTERVAL}秒内,不能重复发送验证码'}
else:
# 判断输入的是邮箱还是手机号
typ = string_help.mail_or_phone(username)
if typ == string_help.MAIL:
code = mail_help.send_vcode(settings.MAIL_SMTP_SERVER, settings.MAIL_FROM_ADDR,settings.MAIL_PASSWORD, username)
resp = {'msg':'验证码已发送,请查阅'}
elif typ == string_help.PHONE:
# 发送短信验证
flag, code = yunpian.send_sms(settings.YUNPIAN_APIKEY, settings.YUNPIAN_TEMPLATE, username)
if not flag:
resp = {'msg':'发送短信失败,请联系管理员'}
else:
resp = {'msg':'验证码已经发送,请查看手机'}
else:
resp = {'msg':'账号不合法,既不是邮箱也不是手机号'}
# 存储验证码
request.session['mail_code'] = code
request.session['mail'] = username
# 存储发送邮件时间
request.session['mail_code_time'] = time.time()
return JsonResponse(resp)