191.基于Django框架发送邮件与手机验证码详解

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

  1. 注释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',
]
  1. 添加配置
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 使用云片网发送短信验证

  1. 云片网网址:https://www.yunpian.com/
  2. 注册账号
  3. 新账户赠送0.5元,可以不用充值测试
  4. 接入短信
  5. 进行个人实名认证
  6. 实名信息审核通过后,设置签名 和 短信模板
  7. 需要获取两个信息:
    • apikey
    • 短信模板
  8. 实现接口,查看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)
  • 1
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

想成为数据分析师的开发工程师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值