目录
🛠️ 示例:用 Python + Pillow 生成图形验证码
验证码是防止机器人或恶意刷接口的常见方式之一。在后端,验证码的生成可以分为文字型、图形型、短信型、邮箱型等,这里我主要讲讲图形验证码和数字验证码的生成逻辑,并举些实用例子。
🔐 一、验证码类型与用途
验证码类型 | 说明 | 常见场景 |
---|---|---|
图形验证码(图片) | 随机字母数字+干扰线 | 登录、注册、防刷接口 |
数字验证码(短信/邮箱) | 4~6 位数字 | 手机验证码、找回密码 |
滑块验证码 | 拖动滑块完成拼图 | 注册/登录前防刷 |
点选验证码 | “请点击所有包含猫的图片” | 高级反机器人验证 |
📸 二、图形验证码的原理(Image Captcha)
🔧 核心流程
-
生成一段随机文本(如:4~6位字母/数字)
-
使用图形库将这段文本画到图像中
-
添加干扰元素(线条、噪点等)
-
将验证码文本保存到 Redis/session 中
-
返回图像(二进制)给前端
🛠️ 示例:用 Python + Pillow 生成图形验证码
安装依赖:
pip install pillow
代码:
# captcha_gen.py
from PIL import Image, ImageDraw, ImageFont, ImageFilter
import random
import string
import io
def generate_captcha_text(length=5):
return ''.join(random.choices(string.ascii_uppercase + string.digits, k=length))
def generate_captcha_image(text):
width, height = 120, 40
image = Image.new('RGB', (width, height), (255, 255, 255))
font = ImageFont.truetype("arial.ttf", 24)
draw = ImageDraw.Draw(image)
# 写入文字
for i, char in enumerate(text):
draw.text((10 + i * 20, 8), char, font=font, fill=(random.randint(0,150), 0, 0))
# 添加干扰线
for _ in range(5):
x1, y1 = random.randint(0, width), random.randint(0, height)
x2, y2 = random.randint(0, width), random.randint(0, height)
draw.line((x1, y1, x2, y2), fill=(0, 0, 0))
# 模糊处理(可选)
image = image.filter(ImageFilter.EDGE_ENHANCE_MORE)
# 转成字节流
byte_io = io.BytesIO()
image.save(byte_io, 'PNG')
byte_io.seek(0)
return byte_io
在 Flask 接口中使用:
# app.py
from flask import Flask, send_file, session
from captcha_gen import generate_captcha_text, generate_captcha_image
app = Flask(__name__)
app.secret_key = 'super-secret-key'
@app.route('/captcha')
def get_captcha():
text = generate_captcha_text()
session['captcha'] = text # 保存验证码内容
image = generate_captcha_image(text)
return send_file(image, mimetype='image/png')
📱 三、数字验证码(短信/邮箱)
核心流程:
-
生成随机 4~6 位数字;
-
将验证码保存到 Redis(设置 5 分钟过期);
-
使用短信服务(如腾讯云、阿里云)或邮件服务(如 SMTP)发送给用户;
-
用户输入后端校验 → 与 Redis 中的验证码比对。
示例:
import random
import redis
r = redis.Redis(host='localhost', port=6379)
def send_code(phone):
code = f"{random.randint(100000, 999999)}"
r.setex(f"code:{phone}", 300, code) # 有效期5分钟
print(f"验证码是 {code}(应该发送短信)")
🎯 四、验证码校验流程
用户输入验证码时的处理逻辑:
def verify_code(phone, user_input):
real_code = r.get(f"code:{phone}")
if not real_code:
return "验证码过期"
if user_input != real_code.decode():
return "验证码错误"
return "验证通过"
✅ 实战建议
建议 | 说明 |
---|---|
使用 Redis 缓存验证码 | 高性能+过期机制天然适合验证码 |
控制验证码发送频率 | 每个 IP/手机号冷却 60 秒 |
设置验证码有效期 | 一般 3~5 分钟 |
加入图形验证码判断 | 多次请求时才出图形验证码,提升体验 |
多渠道验证码备选 | 可以邮箱 + 手机切换使用 |
💡 高级扩展建议
-
接入腾讯云短信、SendGrid 邮件服务;
-
接入极验(GeeTest)或 reCAPTCHA 滑动验证;
-
图形验证码 + 人机验证组合,提高安全性;
-
如果用前端框架,还可以使用base64 图片验证码传输。