Python + Flask 实现验证码功能

作者:user 发布日期: 浏览量:6

验证码

验证码分类

  • 图片验证码
  • 邮箱验证码
  • 短信验证码

验证码实现原理

  • 第一步:前端发起请求
  • 第二步:后端接收到验证码申请请求
  • 第三步:生成验证码
  • 第四步:验证码正确结果存储
  • 第五步:邮箱/短信:发送验证码;图片:发送加过干扰的图片
  • 第六步:用户输入验证码
  • 第七步:验证码比对
  • 第八步:返回是否验证通过

图片验证码生成逻辑

  • 绘制图片
  • 生成随机字符串
  • 字符串绘制到图片上
  • 生成干扰
  • 输出图片验证码

绘制图片验证码

安装依赖

pip install pillow

绘制验证码

"""
  common/utils.py
"""
import random
import string
from io import BytesIO
# 这个 PIL 就是安装的 pillow
from PIL import Image, ImageFont, ImageDraw

"""
  图片验证码
"""
class ImageCode():
    # 获取验证码
    def get_verify_code(self):
        imgage,code = self.draw_verify_code()
        buffer = BytesIO()
        # 将图片保存成二进制流
        imgage.save(buffer, "jpeg")
        # 获取二进制流
        image_b_str = buffer.getvalue()

        return code, image_b_str

    # 绘制验证码
    def draw_verify_code(self):
        # 生成随机字符串
        code = self.get_text()
        # 设置图片的宽和高,在实际项目中最好跟前端约定好显示图片的大小
        width,height = 120,50
        # 绘制图片
        img = Image.new("RGB", (width,height),"white")
        font = ImageFont.truetype(font="C:\\Windows\\Fonts\\Arial.ttf", size=40)
        draw = ImageDraw.Draw(img)
        # 绘制字符串
        for i in range(4):
            draw.text(xy=(random.randint(3,10) + 25 * i, random.randint(3,10)),text=code[i],fill=self.random_color(), font=font)
        # 绘制干扰线
        self.draw_lines(draw,3,width,height)
        img.show()
        return img,code

    # 生成随机字符串
    def get_text(self):
        # 从给定字符串中选 4 位
        # list = random.sample("1234567890abcdefghjkmnpqrstuvwxyz", 4)
        # 字母大小写 + 数字
        list = random.sample(string.ascii_letters + string.digits, 4)

        return "".join(list)

    # 生成随机颜色值
    def random_color(self):
        red = random.randint(0,255)
        green = random.randint(0,255)
        blue = random.randint(0,255)

        return red,green,blue

    # 绘制干扰线
    def draw_lines(self, draw, count, width, height):
        for c in range(count):
            x1 = random.randint(0,width)
            y1 = random.randint(0,height)
            x2 = random.randint(0, width)
            y2 = random.randint(0, height)
            draw.line([(x1,y1),(x2,y2)], fill="black", width=2)

将验证码图片返回给前端

"""
  controller/userController.py
  获取图片验证码
"""
@user.route("/getImgCode", methods=["get"])
def get_code():
    code, image_b_str = ImageCode().get_verify_code()
    img_code = make_response(image_b_str)
    img_code.headers["Content-Type"] = "image/jpeg"
    # 存储在内存之中,暂时存在 session
    session["vcode"] = code.lower()
    logging.info("vcode: " + code.lower())
    return img_code

邮箱验证码

"""
  config/config.py
"""
email_name = '[email protected]'  # 服务邮箱
passwd = '你自己邮箱的授权码'  # 授权码

发送验证码到用户邮箱

import random
import smtplib
import string
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from config.config import config
from config.settings import env

"""
  随机生成邮箱验证码
"""
def gen_email_code():
    list = random.sample(string.ascii_letters+string.digits,6)
    return "".join(list)

"""
  发送到邮箱
"""
def send_email(email,code):
    print(code)
    emall_name = config[env].email_name # 服务邮箱
    passwd = config[env].passwd         # 服务邮箱授权码
    msg_to = email                      # 发送的目标邮箱
    content = "您的验证码:<h1 style='color:red'>{}</h1>".format(code)
    msg = MIMEMultipart()
    msg["Subject"] = "博客验证码"
    msg["From"] = emall_name
    msg["To"] = msg_to
    # 发送邮件正文,html格式的
    msg.attach(MIMEText(content,"html","utf-8"))
    s = smtplib.SMTP_SSL("smtp.qq.com", 465) # 邮箱服务器及端口号
    s.login(emall_name,passwd)
    s.sendmail(emall_name,msg_to,msg.as_string())

用户输入邮箱并获取验证码

"""
  发送验证码到用户邮箱
"""
@user.route("/emailCode", methods=["post"])
def email_code():
    # email = json.loads(request.data).get("email")
    email = request.form.get("email")
    # 简单的邮箱格式验证
    if not re.match(".+@.+\..+", email):
        return ResponseStatusCode.Message.other("无效的邮箱")
    # 生成邮箱验证码的随机字符串
    code = gen_email_code()
    # 发送邮件
    try:
        send_email(email, code)
        session['ecode'] = code.lower()
        return ResponseStatusCode.Message.success("邮件发送成功")
    except Exception as e:
        print(e)
        return ResponseStatusCode.Message.error("邮件发送失败")