图形验证码怎么生成?

wen python案例 2

本文目录导读:

图形验证码怎么生成?

  1. 核心生成流程(后端)
  2. 全代码示例(Python + Flask)
  3. 其他实现方式
  4. 安全与最佳实践

我来为你详细介绍一下图形验证码的生成方法,这通常包括前端展示后端生成两个部分。

核心生成流程(后端)

最主流的方式是后端生成图片并返回,前端负责展示,流程如下:

  1. 生成随机字符串:生成一组随机的字母、数字或汉字。
  2. 存放到Session/Redis:将此字符串(原文)与当前用户的会话(Session)或临时缓存(如Redis,用于分布式系统)关联起来。
    • 不存图片内容,只存文字:服务器生成图片后,通常只保存验证码的文字到内存中,用于后续校验,图片本身不保存。
  3. 绘制图片:用服务器端绘图库(如Java的BufferedImage、Python的Pillow、PHP的GD库),在内存中绘制一张包含该字符串的图片,并加入干扰元素(线条、噪点、扭曲等)。
  4. 输出图片流:将生成的图片以字节流的形式输出到HTTP响应中,并设置响应头,让浏览器将其作为图片渲染。
  5. 前端展示:前端用一个<img>标签或<canvas>src指向后端生成验证码的API地址。

全代码示例(Python + Flask)

这是一个超简单的示例,用Python的PillowFlask实现。

安装依赖

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 = ?”
滑块验证码 拖动滑块到缺口位置 高(复杂前后端交互)
点选验证码 按顺序点击图片中的指定物体 高(需要图库)

安全与最佳实践

  1. 一次性使用:验证码校验成功或失败后,立刻从Session/Redis中删除,防止重复使用。
  2. 设置过期时间:验证码生成后,建议5分钟内有效,可以存入Redis并设置TTL。
  3. 防暴力破解
    • 限制请求频率:同一IP短时间内连续请求验证码超过阈值,暂时封禁。
    • 增加复杂度:加大干扰、扭曲、噪点,让OCR难以识别。
  4. 区分大小写:为降低用户输入困难,建议不区分大小写,生成时统一转大写,校验时也转大写。
  5. 无状态Token化(推荐):在分布式系统中,Session可能不共享,建议:
    • 生成验证码后将文本加密(或计算哈希),作为captcha_token返回给前端。
    • 前端提交时将 captcha_token 和用户输入的验证码一起提交。
    • 后端用同样的密钥解密或哈希比对,无需Session。
  • 简单场景:使用后端绘图库(如Pillow、Java Graphics2D)生成简单的数字字母验证码,存Session。
  • 生产环境:推荐使用第三方服务(reCAPTCHA等)或采用更复杂的滑块验证码,安全性高且维护成本低。
  • 关键:不要在验证码生成逻辑中向任何人(包括前端)泄露正确的验证码文本。

抱歉,评论功能暂时关闭!