本文目录导读:

我来为你详细介绍一下图形验证码的生成方法,这通常包括前端展示和后端生成两个部分。
核心生成流程(后端)
最主流的方式是后端生成图片并返回,前端负责展示,流程如下:
- 生成随机字符串:生成一组随机的字母、数字或汉字。
- 存放到Session/Redis:将此字符串(原文)与当前用户的会话(Session)或临时缓存(如Redis,用于分布式系统)关联起来。
- 不存图片内容,只存文字:服务器生成图片后,通常只保存验证码的文字到内存中,用于后续校验,图片本身不保存。
- 绘制图片:用服务器端绘图库(如Java的
BufferedImage、Python的Pillow、PHP的GD库),在内存中绘制一张包含该字符串的图片,并加入干扰元素(线条、噪点、扭曲等)。 - 输出图片流:将生成的图片以字节流的形式输出到HTTP响应中,并设置响应头,让浏览器将其作为图片渲染。
- 前端展示:前端用一个
<img>标签或<canvas>,src指向后端生成验证码的API地址。
全代码示例(Python + Flask)
这是一个超简单的示例,用Python的Pillow和Flask实现。
安装依赖
pip install flask Pillow
核心代码
import random
import string
from io import BytesIO
from flask import Flask, session, make_response
from PIL import Image, ImageDraw, ImageFont
app = Flask(__name__)
app.secret_key = 'your_secret_key' # 必须要有密钥才能使用session
# 生成随机验证码文本
def generate_code(length=4):
# 移除容易混淆的字符如 1, l, 0, O
chars = string.ascii_uppercase + string.digits
chars = chars.replace('I', '').replace('L', '').replace('O', '').replace('0', '')
return ''.join(random.choices(chars, k=length))
# 生成验证码图片
def generate_image(code):
width, height = 120, 40
# 1. 创建画布(背景白色)
image = Image.new('RGB', (width, height), (255, 255, 255))
draw = ImageDraw.Draw(image)
# 2. 添加干扰点
for _ in range(100):
x, y = random.randint(0, width), random.randint(0, height)
draw.point((x, y), fill=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
# 3. 添加干扰线
for _ in range(3):
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=(random.randint(0, 255), random.randint(0, 255), random.randint(0, 255)))
# 4. 绘制文字(使用默认字体)
font = ImageFont.load_default()
for i, char in enumerate(code):
# 每个字符随机偏移和旋转角度(简化版仅偏移)
x = 10 + i * 25 + random.randint(-5, 5)
y = random.randint(5, 15)
# 随机颜色
color = (random.randint(50, 200), random.randint(50, 200), random.randint(50, 200))
draw.text((x, y), char, font=font, fill=color)
# 5. 返回图片二进制流
buf = BytesIO()
image.save(buf, format='PNG')
buf.seek(0)
return buf
@app.route('/captcha')
def captcha():
# 1. 生成验证码文本
code = generate_code()
# 2. 存入Session(用于后续校验)
session['captcha_code'] = code
# 3. 生成图片
img_buf = generate_image(code)
# 4. 返回图片流
response = make_response(img_buf.getvalue())
response.content_type = 'image/png'
# 禁止缓存,确保每次请求都获取新验证码
response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
return response
if __name__ == '__main__':
app.run(debug=True)
前端展示
<img src="/captcha" id="captcha_img" onclick="this.src='/captcha?'+Math.random()" />
点击图片时,会重新请求验证码(加随机数防止缓存)。
其他实现方式
纯前端生成(不推荐用于安全场景)
- Canvas + JS:在前端用JavaScript的Canvas API生成验证码图片。
- SVG:生成包含随机文字的SVG矢量图。
- 缺点:验证码文本暴露在前端JS代码中,很容易被破解,不能用于真正的安全验证,仅可用于防误触等低安全需求。
使用第三方验证码服务(推荐用于高安全场景)
对于重要业务(登录、支付),建议直接使用专业服务:
- Google reCAPTCHA:全球通用,用户体验好,点击“我不是机器人”即可。
- 阿里云/腾讯云的验证码服务:智能、安全,支持滑块、点选等。
- hCaptcha:reCAPTCHA的替代方案,注重隐私。
优点:AI难以破解,无需自己维护复杂的反破解逻辑。
常见的图形验证码形式
| 类型 | 描述 | 实现难度 | 安全性 |
|---|---|---|---|
| 数字+字母 | 经典的4-6位随机字符,加干扰线/噪点 | 低 | 低 |
| 汉字验证码 | 显示中文词语,用户输入 | 中(需中文字体) | 低 |
| 算术验证码 | 如“25 + 17 = ?” | 低 | 低 |
| 滑块验证码 | 拖动滑块到缺口位置 | 高(复杂前后端交互) | 高 |
| 点选验证码 | 按顺序点击图片中的指定物体 | 高(需要图库) | 高 |
安全与最佳实践
- 一次性使用:验证码校验成功或失败后,立刻从Session/Redis中删除,防止重复使用。
- 设置过期时间:验证码生成后,建议5分钟内有效,可以存入Redis并设置TTL。
- 防暴力破解:
- 限制请求频率:同一IP短时间内连续请求验证码超过阈值,暂时封禁。
- 增加复杂度:加大干扰、扭曲、噪点,让OCR难以识别。
- 区分大小写:为降低用户输入困难,建议不区分大小写,生成时统一转大写,校验时也转大写。
- 无状态Token化(推荐):在分布式系统中,Session可能不共享,建议:
- 生成验证码后将文本加密(或计算哈希),作为
captcha_token返回给前端。 - 前端提交时将
captcha_token和用户输入的验证码一起提交。 - 后端用同样的密钥解密或哈希比对,无需Session。
- 生成验证码后将文本加密(或计算哈希),作为
- 简单场景:使用后端绘图库(如Pillow、Java Graphics2D)生成简单的数字字母验证码,存Session。
- 生产环境:推荐使用第三方服务(reCAPTCHA等)或采用更复杂的滑块验证码,安全性高且维护成本低。
- 关键:不要在验证码生成逻辑中向任何人(包括前端)泄露正确的验证码文本。