Python中三大主流图片验证码库使用推荐与实践指南

作者:

文章目录
  • 最近在做一个 Web 项目的时候,需要添加验证码功能来防止恶意注册和破解。刚开始想着自己写一个简单的验证码生成器,但发现要考虑的东西还挺多的:图片生成、字符扭曲、干扰线、过期时间、安全性等等。后来发现其实有很多现成的库可以用,但选择哪个库、怎么集成到项目中,又是一个问题。 相信很多 Python 开发者都遇到过类似的问题:项目需要验证码功能,但不知道选哪个库,也不知道怎么集成。今天我们就来聊聊 Python 中常用的图片验证码库,以及如何在实际项目中应用它们。
  • 在深入讨论具体的库之前,我们先聊聊为什么需要验证码,以及在实际开发中会遇到哪些痛点。
  • 根据当前的技术趋势,下面是最常用且好用的图片验证码库,以及它们的特点和适用场景。
  • 下面我们来看看如何在实际项目中引入和使用这些验证码库。
  • 在实际项目中,除了基本的验证码功能,我们还需要考虑很多细节。
  • 对于对安全性要求很高的商业项目,可以考虑使用商业验证码方案。下面是几个主流方案的对比: 方案 优点 缺点 适用场景 自建 captcha 免费、可控、无第三方依赖 安全性较低、需自己维护 内部系统、中小项目 django-simple-captcha Django 集成好、功能完善 仅限 Django、样式固定 Django 项目 极验/腾讯云 安全性高、智能验证、防破解 收费、第三方依赖 对安全性要求高的商业项目 自建方案:适合内部系统或中小型项目,成本低但安全性相对较低。 Django 方案:适合 Django 项目,集成方便但灵活性有限。 商业方案:适合对安全性要求很高的商业项目,安全性高但需要付费。
  • 让我们看看几个实际应用场景,了解如何在不同情况下选择合适的方案。
  • 选择验证码库时,需要根据项目需求来决定: 快速开发:Django 项目用 django-simple-captcha,非 Django 项目用 captcha。 高安全性需求:考虑商业方案(极验、腾讯云验证码)。 完全自定义:基于 PIL/Pillow + captcha 自行开发。 最简单的起步方案: # 最小化实现 pip install captcha pillow # 生成验证码 from captcha.image import ImageCaptcha image = ImageCaptcha() data = image.generate(‘1234’) with open(‘captcha.png’, ‘wb’) as f: f.write(data.getvalue()) 关键点总结: 选择合适的库:根据项目框架和需求选择合适的库 安全性考虑:添加过期时间、一次性使用、频率限制等 用户体验:平衡安全性和用户体验,不要过度复杂 生产环境:考虑日志记录、频率限制、前后端分离等 希望这篇文章能帮助你选择合适的验证码库,并在实际项目中正确使用它们!
  • 下面是一个完整的 Flask 示例,展示了如何在实际项目中使用验证码: from flask import Flask, request, session, make_response, render_template_string from captcha.image import ImageCaptcha import random import time import io app = Flask(__name__) app.secret_key = ‘your-secret-key-change-in-production’ # HTML 模板 HTML_TEMPLATE = “”” <!DOCTYPE html> <html> <head> <title>验证码示例</title> <style> body { font-family: Arial, sans-serif; max-width: 500px; margin: 50px auto; padding: 20px; } .form-group { margin-bottom: 15px; } label { display: block; margin-bottom: 5px; } input[type=”text”], input[type=”password”] { width: 100%; padding: 8px; box-sizing: border-box; } .captcha-group { display: flex; align-items: center; gap: 10px; } .captcha-img { cursor: pointer; border: 1px solid #ddd; padding: 5px; } .refresh-link { color: #007bff; text-decoration: none; } .refresh-link:hover { text-decoration: underline; } button { background-color: #007bff; color: white; padding: 10px 20px; border: none; cursor: pointer; } .message { margin-top: 10px; padding: 10px; border-radius: 4px; } .success { background-color: #d4edda; color: #155724; } .error { background-color: #f8d7da; color: #721c24; } </style> </head> <body> <h2>登录示例</h2> <form method=”POST” action=”/login”> <div class=”form-group”> <label>用户名:</label> <input type=”text” name=”username” required> </div> <div class=”form-group”> <label>密码:</label> <input type=”password” name=”password” required> </div> <div class=”form-group”> <label>验证码:</label> <div class=”captcha-group”> <input type=”text” name=”captcha” required style=”flex: 1;”> <img id=”captcha-img” class=”captcha-img” src=”/captcha” onclick=”refreshCaptcha()” alt=”验证码”> <a href=”javascript:;” rel=”external nofollow” rel=”external nofollow” onclick=”refreshCaptcha()” class=”refresh-link”>换一张</a> </div> </div> <button type=”submit”>登录</button> </form> {% if message %} <div class=”message {{ message_type }}”> {{ message }} </div> {% endif %} <script> function refreshCaptcha() { document.getElementById(‘captcha-img’).src = ‘/captcha?’ + Date.now(); } </script> </body> </html> “”” def generate_captcha_text(length=4): “””生成验证码文本(排除易混淆字符)””” chars = ‘ABCDEFGHJKLMNPQRSTUVWXYZ23456789’ return ”.join(random.choices(chars, k=length)) def generate_captcha(): “””生成验证码图片””” captcha_text = generate_captcha_text() # 创建验证码图像 image = ImageCaptcha(width=120, height=40) data = image.generate(captcha_text) # 保存验证码到 session(带时间戳) session[‘captcha’] = captcha_text session[‘captcha_time’] = time.time() return data @app.route(‘/’) def index(): “””首页””” return render_template_string(HTML_TEMPLATE) @app.route(‘/captcha’) def get_captcha(): “””获取验证码图片””” image_data = generate_captcha() response = make_response(image_data.getvalue()) response.headers[‘Content-Type’] = ‘image/png’ # 防止缓存 response.headers[‘Cache-Control’] = ‘no-cache, no-store, must-revalidate’ response.headers[‘Pragma’] = ‘no-cache’ response.headers[‘Expires’] = ‘0’ return response def verify_captcha(user_input, timeout=300): “””验证验证码(带过期时间)””” if ‘captcha’ not in session or ‘captcha_time’ not in session: return False, ‘验证码已过期,请刷新’ # 检查是否过期(5分钟) if time.time() – session[‘captcha_time’] > timeout: session.pop(‘captcha’, None) session.pop(‘captcha_time’, None) return False, ‘验证码已过期,请刷新’ # 验证(忽略大小写) if user_input.upper() != session[‘captcha’].upper(): return False, ‘验证码错误’ # 验证成功后清除验证码(一次性使用) session.pop(‘captcha’, None) session.pop(‘captcha_time’, None) return True, ‘验证成功’ @app.route(‘/login’, methods=[‘GET’, ‘POST’]) def login(): “””登录处理””” if request.method == ‘POST’: username = request.form.get(‘username’, ”) password = request.form.get(‘password’, ”) captcha_input = request.form.get(‘captcha’, ”) # 验证验证码 is_valid, message = verify_captcha(captcha_input) if not is_valid: return render_template_string( HTML_TEMPLATE, message=message, message_type=’error’ ) # 这里处理实际的登录逻辑 # 示例:简单的用户名密码验证 if username == ‘admin’ and password == ‘123456’: return render_template_string( HTML_TEMPLATE, message=’登录成功!’, message_type=’success’ ) else: return render_template_string( HTML_TEMPLATE, message=’用户名或密码错误’, message_type=’error’ ) return render_template_string(HTML_TEMPLATE) if __name__ == ‘__main__’: app.run(debug=True) 使用说明: 1.安装依赖: pip install flask captcha pillow 2.运行应用: python app.py 3.访问应用:打开浏览器访问 http://localhost:5000 4.测试登录: 用户名:admin 密码:123456 验证码:输入图片中显示的验证码 这个 Demo 展示了: 验证码生成:使用 captcha 库生成验证码图片 验证码验证:带过期时间的一次性验证 前端集成:点击图片或链接刷新验证码 用户体验:清晰的错误提示和成功提示 你可以根据实际需求修改和扩展这个示例。 以上就是Python中三大主流图片验证码库使用推荐与实践指南的详细内容,更多关于Python图片验证码库的资料请关注风君子博客其它相关文章! 您可能感兴趣的文章: 使用 Python 和 LabelMe 实现图片验证码的自动标注功能 利用Python实现生成并识别图片验证码 Python进行图片验证码识别方法步骤 使用Python生成随机图片验证码的代码详解 Python中识别图片/滑块验证码准确率极高的ddddocr库详解 Python Flask实现图片验证码与邮箱验证码流程详细讲解 python3定位并识别图片验证码实现自动登录功能
  • 目录
    • 前言
    • 为什么需要验证码
      • 常见的安全问题
      • 开发中的痛点
    • 主流图片验证码库推荐
      • captcha:Python 原生库,推荐度高
      • django-simple-captcha:Django 专属方案
      • kaptcha:Java 转 Python 实现
      • 商业方案:滑动验证码和行为验证码
    • Python 项目引入指南
      • 基础安装配置
      • 方案一:使用 captcha 库(Flask/FastAPI 通用)
      • 方案二:Django 项目集成 django-simple-captcha
      • 方案三:高级自定义验证码
    • 最佳实践建议
      • 安全性增强
      • 前端集成示例
      • 生产环境建议
    • 商业方案对比
      • 实际应用场景
        • 场景一:内部管理系统
        • 场景二:用户注册登录
        • 场景三:API 接口保护
        • 场景四:前后端分离项目
      • 总结
        • 完整可运行 Demo 代码

          最近在做一个 Web 项目的时候,需要添加验证码功能来防止恶意注册和破解。刚开始想着自己写一个简单的验证码生成器,但发现要考虑的东西还挺多的:图片生成、字符扭曲、干扰线、过期时间、安全性等等。后来发现其实有很多现成的库可以用,但选择哪个库、怎么集成到项目中,又是一个问题。

          相信很多 Python 开发者都遇到过类似的问题:项目需要验证码功能,但不知道选哪个库,也不知道怎么集成。今天我们就来聊聊 Python 中常用的图片验证码库,以及如何在实际项目中应用它们。

          在深入讨论具体的库之前,我们先聊聊为什么需要验证码,以及在实际开发中会遇到哪些痛点。

          现在的 Web 应用面临很多安全威胁,验证码是其中一种重要的防护手段:

          恶意注册:很多网站都会遇到恶意注册的问题,有人用脚本批量注册账号,占用服务器资源,甚至用来发送垃圾信息。如果没有验证码,这些脚本可以轻松地自动化注册流程。

          恶意破解:对于登录功能,如果没有验证码,攻击者可以用脚本尝试大量的用户名密码组合。虽然现在很多系统都有登录失败次数限制,但验证码可以进一步增加攻击成本。

          接口滥用:很多 API 接口如果没有验证码保护,可能会被恶意调用,比如发送短信验证码、发送邮件等。这些接口如果被滥用,不仅会消耗资源,还可能产生费用。

          爬虫防护:虽然验证码不能完全阻止爬虫,但可以增加爬虫的成本。对于一些简单的爬虫,验证码就能起到很好的防护作用。

          在实际开发中,实现验证码功能会遇到很多痛点:

          图片生成复杂:如果要自己实现验证码生成,需要考虑很多细节:字体选择、字符扭曲、干扰线、干扰点、颜色搭配等等。这些细节处理不好,验证码要么太简单容易被识别,要么太复杂用户体验不好。

          安全性问题:验证码的安全性是一个大问题。如果验证码太简单,容易被 OCR 识别;如果验证码太复杂,用户体验不好。而且还要考虑验证码的过期时间、一次性使用、防止重放攻击等问题。

          框架集成:不同的 Web 框架(Flask、Django、FastAPI 等)集成验证码的方式不一样,需要针对性地适配。而且还要考虑前后端分离的场景,验证码如何通过 API 返回。

          用户体验:验证码的用户体验也很重要。如果验证码看不清,用户会抱怨;如果验证码刷新不方便,用户会烦躁。而且现在很多用户习惯使用移动端,验证码在小屏幕上的显示效果也要考虑。

          维护成本:如果自己实现验证码功能,后续的维护成本也不低。比如要更新字体、调整样式、修复 bug 等等。而使用现成的库,可以降低维护成本。

          根据当前的技术趋势,下面是最常用且好用的图片验证码库,以及它们的特点和适用场景。

          captcha 是一个由 Google 开发维护的 Python 库,GitHub 上有 1.2k+ stars。它的特点是简单易用,支持自定义,适合各种 Python Web 框架。

          优点:

          • 简单易用,API 设计清晰
          • 支持自定义图片大小、字体、颜色等
          • 不依赖特定的 Web 框架,可以在 Flask、Django、FastAPI 等框架中使用
          • 由 Google 维护,代码质量有保障

          缺点:

          • 功能相对简单,不支持复杂的验证码样式
          • 安全性相对较低,容易被 OCR 识别

          适用场景:

          • 内部系统或中小型项目
          • 对安全性要求不是特别高的场景
          • 需要快速集成验证码功能的项目

          基本使用:

          from captcha.image import ImageCaptcha
          
          # 创建验证码图像
          image = ImageCaptcha(width=280, height=90)
          data = image.generate('1234')
          image.write('1234', 'out.png')
          

          这个库的使用非常简单,只需要几行代码就能生成验证码图片。但需要注意的是,它生成的验证码相对简单,安全性不是特别高。

          django-simple-captcha 是专门为 Django 框架设计的验证码库,GitHub 上有 1.6k+ stars。它的特点是 Django 集成度最高,开箱即用。

          优点:

          • 与 Django 深度集成,使用非常方便
          • 支持 Django Forms,可以直接在表单中使用
          • 功能完善,支持多种验证码样式
          • 社区活跃,文档完善

          缺点:

          • 仅限 Django 项目使用
          • 样式相对固定,自定义程度有限

          适用场景:

          • Django 项目
          • 需要快速集成验证码功能的 Django 应用
          • 不需要太多自定义的场景

          基本使用:

          # settings.py
          INSTALLED_APPS = [
              'captcha',
          ]
          
          # models.py
          from django import forms
          from captcha.fields import CaptchaField
          
          class ContactForm(forms.Form):
              captcha = CaptchaField()
          

          这个库最大的优势就是与 Django 的集成非常好,如果你用的是 Django 框架,这个库是最佳选择。

          kaptcha 是模仿 Java 版 Kaptcha 的 Python 实现,功能相对强大。

          优点:

          • 功能强大,支持多种验证码样式
          • 可以生成复杂的验证码图片

          缺点:

          • 文档相对较少
          • 社区活跃度不高
          • 使用相对复杂

          适用场景:

          • 需要复杂验证码样式的项目
          • 对 Java Kaptcha 熟悉的开发者

          除了开源的库,还有一些商业方案,比如极验、腾讯云验证码、阿里云验证码等。这些方案通常提供滑动验证码、行为验证码等更高级的验证方式。

          极验(geetest):

          • 识别率高,安全性强
          • 支持多种验证方式(滑动、点选、语音等)
          • 有免费额度,超出后收费

          腾讯云验证码:

          • 智能验证,多种形式
          • 与腾讯云服务集成
          • 按调用次数收费

          阿里云验证码:

          • 风险识别,无感验证
          • 与阿里云服务集成
          • 按调用次数收费

          适用场景:

          • 对安全性要求很高的商业项目
          • 有预算支持的项目
          • 需要高级验证方式的场景

          下面我们来看看如何在实际项目中引入和使用这些验证码库。

          首先,我们需要安装相应的库:

          # 安装 captcha 库(Flask/FastAPI 通用)
          pip install captcha pillow
          
          # 安装 django-simple-captcha(Django 项目)
          pip install django-simple-captcha
          

          pillow 是 Python 的图像处理库,captcha 库依赖它来生成图片。如果你用的是 Django,还需要安装 django-simple-captcha

          如果你用的是 Flask 或 FastAPI,可以使用 captcha 库。下面是一个完整的 Flask 示例:

          from flask import Flask, request, session, make_response
          from captcha.image import ImageCaptcha
          import random
          import io
          
          app = Flask(__name__)
          app.secret_key = 'your-secret-key'
          
          def generate_captcha():
              """生成验证码"""
              # 生成随机验证码文本(排除易混淆字符)
              chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
              captcha_text = ''.join(random.choices(chars, k=4))
              
              # 创建验证码图像
              image = ImageCaptcha(width=120, height=40)
              data = image.generate(captcha_text)
              
              # 保存验证码到 session
              session['captcha'] = captcha_text
              
              return data
          
          @app.route('/captcha')
          def get_captcha():
              """获取验证码图片"""
              image_data = generate_captcha()
              
              response = make_response(image_data.getvalue())
              response.headers['Content-Type'] = 'image/png'
              # 防止缓存,确保每次请求都是新的验证码
              response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
              response.headers['Pragma'] = 'no-cache'
              response.headers['Expires'] = '0'
              
              return response
          
          @app.route('/verify', methods=['POST'])
          def verify_captcha():
              """验证用户输入"""
              user_input = request.form.get('captcha', '').upper()
              server_captcha = session.get('captcha', '')
              
              if user_input == server_captcha:
                  # 验证成功后清除验证码,防止重复使用
                  session.pop('captcha', None)
                  return {'success': True, 'message': '验证码正确'}
              else:
                  return {'success': False, 'message': '验证码错误'}, 400
          

          这个方案的关键点:

          • 生成验证码:使用 ImageCaptcha 生成图片,并将验证码文本保存到 session
          • 返回图片:通过 HTTP 响应返回图片,并设置合适的响应头防止缓存
          • 验证输入:从 session 中读取验证码,与用户输入进行比较
          • 安全性:验证成功后清除 session 中的验证码,防止重复使用

          如果你用的是 Django,使用 django-simple-captcha 会更方便:

          第一步:配置 settings.py

          # settings.py
          INSTALLED_APPS = [
              'captcha',
          ]
          
          # 验证码设置
          CAPTCHA_LENGTH = 4  # 字符数
          CAPTCHA_TIMEOUT = 5  # 过期时间(分钟)
          CAPTCHA_NOISE_FUNCTIONS = ('captcha.helpers.noise_null',)
          CAPTCHA_IMAGE_SIZE = (120, 40)
          

          第二步:在 form 中使用

          # forms.py
          from django import forms
          from captcha.fields import CaptchaField
          
          class LoginForm(forms.Form):
              username = forms.CharField()
              password = forms.CharField(widget=forms.PasswordInput)
              captcha = CaptchaField()
          

          第三步:视图使用

          # views.py
          from django.shortcuts import render
          from .forms import LoginForm
          
          def login_view(request):
              if request.method == 'POST':
                  form = LoginForm(request.POST)
                  if form.is_valid():
                      # 验证通过,处理登录逻辑
                      username = form.cleaned_data['username']
                      password = form.cleaned_data['password']
                      # ... 登录逻辑
              else:
                  form = LoginForm()
              
              return render(request, 'login.html', {'form': form})
          

          第四步:模板中使用

          <!-- login.html -->
          <form method="post">
              {% csrf_token %}
              {{ form.as_p }}
              <input type="submit" value="登录">
          </form>
          

          这个方案的优势是集成度非常高,Django 会自动处理验证码的生成、验证等逻辑,你只需要在表单中添加一个字段就行。

          如果你需要更复杂的验证码样式,可以基于 PIL/Pillow 自己实现:

          from captcha.image import ImageCaptcha
          from PIL import Image, ImageDraw, ImageFont, ImageFilter
          import random
          import string
          import io
          
          class AdvancedCaptcha:
              def __init__(self, width=160, height=60):
                  self.width = width
                  self.height = height
                  self.font_size = 40
                  
              def generate_text(self, length=4):
                  """生成验证码文本(排除易混淆字符)"""
                  chars = string.ascii_uppercase + string.digits
                  exclude_chars = {'0', 'O', '1', 'I', 'L'}
                  chars = [c for c in chars if c not in exclude_chars]
                  return ''.join(random.choices(chars, k=length))
              
              def create_image(self, text):
                  """创建验证码图像(添加干扰)"""
                  # 创建画布
                  image = Image.new('RGB', (self.width, self.height), (255, 255, 255))
                  draw = ImageDraw.Draw(image)
                  
                  # 添加随机干扰点
                  for _ in range(200):
                      x = random.randint(0, self.width)
                      y = random.randint(0, self.height)
                      draw.point((x, y), fill=self._random_color(150, 250))
                  
                  # 添加随机干扰线
                  for _ in range(5):
                      x1 = random.randint(0, self.width)
                      y1 = random.randint(0, self.height)
                      x2 = random.randint(0, self.width)
                      y2 = random.randint(0, self.height)
                      draw.line([(x1, y1), (x2, y2)], fill=self._random_color(100, 200), width=1)
                  
                  # 绘制文字
                  try:
                      font = ImageFont.truetype('arial.ttf', self.font_size)
                  except:
                      font = ImageFont.load_default()
                  
                  # 文字扭曲效果
                  for i, char in enumerate(text):
                      # 每个字符随机偏移
                      x = 20 + i * 35 + random.randint(-5, 5)
                      y = 5 + random.randint(-5, 5)
                      draw.text((x, y), char, font=font, fill=self._random_color(20, 120))
                  
                  # 添加滤镜效果
                  image = image.filter(ImageFilter.SMOOTH_MORE)
                  
                  # 转换为字节流
                  img_byte_arr = io.BytesIO()
                  image.save(img_byte_arr, format='PNG')
                  img_byte_arr = img_byte_arr.getvalue()
                  
                  return img_byte_arr, text
              
              def _random_color(self, low, high):
                  """生成随机颜色"""
                  return (random.randint(low, high), 
                          random.randint(low, high), 
                          random.randint(low, high))
          

          这个方案的优势是可以完全自定义验证码的样式,但实现复杂度也更高。

          在实际项目中,除了基本的验证码功能,我们还需要考虑很多细节。

          添加过期时间:验证码不应该永久有效,应该设置过期时间。比如 5 分钟后自动失效:

          import time
          from flask import session
          
          def set_captcha_session(text):
              session['captcha'] = text
              session['captcha_time'] = time.time()
          
          def verify_captcha_with_timeout(user_input, timeout=300):  # 5分钟过期
              if 'captcha' not in session or 'captcha_time' not in session:
                  return False
              
              if time.time() - session['captcha_time'] > timeout:
                  # 清理过期验证码
                  session.pop('captcha', None)
                  session.pop('captcha_time', None)
                  return False
              
              return user_input.upper() == session['captcha'].upper()
          

          一次性使用:验证码应该是一次性的,验证成功后立即清除,防止重复使用。

          大小写不敏感:验证码验证时应该忽略大小写,提升用户体验。

          防止重放攻击:每次验证后都应该清除验证码,防止攻击者重复使用同一个验证码。

          前端集成验证码时,需要考虑用户体验:

          <!-- HTML前端代码 -->
          <form id="login-form">
              <input type="text" name="username" placeholder="用户名">
              <input type="password" name="password" placeholder="密码">
              <div>
                  <input type="text" name="captcha" placeholder="验证码">
                  <img id="captcha-img" src="/captcha" 
                       onclick="this.src='/captcha?'+Date.now()" 
                       style="cursor:pointer; vertical-align:middle;">
                  <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  onclick="refreshCaptcha()">换一张</a>
              </div>
              <button type="submit">登录</button>
          </form>
          
          <script>
          function refreshCaptcha() {
              // 通过添加时间戳参数强制刷新
              document.getElementById('captcha-img').src = '/captcha?' + Date.now();
          }
          </script>
          

          关键点:

          • 点击图片刷新:用户可以点击验证码图片来刷新
          • 换一张链接:提供明确的刷新入口
          • 防止缓存:通过添加时间戳参数防止浏览器缓存

          在生产环境中,我们还需要考虑更多问题:

          频率限制:对验证码请求进行 IP 限制,比如 60 秒内最多 5 次。这样可以防止恶意请求:

          from flask import request
          from functools import wraps
          import time
          
          # 简单的内存缓存(生产环境建议用 Redis)
          request_cache = {}
          
          def rate_limit(max_requests=5, window=60):
              def decorator(f):
                  @wraps(f)
                  def wrapper(*args, **kwargs):
                      ip = request.remote_addr
                      now = time.time()
                      
                      if ip in request_cache:
                          requests = [r for r in request_cache[ip] if now - r < window]
                          if len(requests) >= max_requests:
                              return {'error': '请求过于频繁'}, 429
                          requests.append(now)
                          request_cache[ip] = requests
                      else:
                          request_cache[ip] = [now]
                      
                      return f(*args, **kwargs)
                  return wrapper
              return decorator
          
          @app.route('/captcha')
          @rate_limit(max_requests=5, window=60)
          def get_captcha():
              # ... 生成验证码
          

          验证码多样性:可以混合使用数字、字母、算术验证码等,增加破解难度。

          日志记录:记录验证失败次数,如果某个 IP 连续失败多次,可以临时封禁。

          前后端分离:如果前后端分离,API 可以返回 base64 格式的验证码:

          import base64
          
          @app.route('/api/captcha')
          def get_captcha_api():
              image_data, text = generate_captcha()
              base64_data = base64.b64encode(image_data.getvalue()).decode()
              
              # 保存验证码到 session 或 Redis
              session['captcha'] = text
              
              return {
                  'image': f'data:image/png;base64,{base64_data}',
                  'expires_in': 300  # 过期时间(秒)
              }
          

          CDN 缓存:静态验证码图片可以考虑 CDN 缓存,但要注意防止缓存导致的问题。

          对于对安全性要求很高的商业项目,可以考虑使用商业验证码方案。下面是几个主流方案的对比:

          方案 优点 缺点 适用场景
          自建 captcha 免费、可控、无第三方依赖 安全性较低、需自己维护 内部系统、中小项目
          django-simple-captcha Django 集成好、功能完善 仅限 Django、样式固定 Django 项目
          极验/腾讯云 安全性高、智能验证、防破解 收费、第三方依赖 对安全性要求高的商业项目

          自建方案:适合内部系统或中小型项目,成本低但安全性相对较低。

          Django 方案:适合 Django 项目,集成方便但灵活性有限。

          商业方案:适合对安全性要求很高的商业项目,安全性高但需要付费。

          让我们看看几个实际应用场景,了解如何在不同情况下选择合适的方案。

          对于内部管理系统,对安全性要求不是特别高,可以选择简单的方案:

          # 使用 captcha 库,简单快速
          from captcha.image import ImageCaptcha
          from flask import Flask, session, make_response
          
          app = Flask(__name__)
          app.secret_key = 'your-secret-key'
          
          @app.route('/captcha')
          def get_captcha():
              image = ImageCaptcha(width=120, height=40)
              captcha_text = ''.join(random.choices('0123456789', k=4))
              data = image.generate(captcha_text)
              session['captcha'] = captcha_text
              response = make_response(data.getvalue())
              response.headers['Content-Type'] = 'image/png'
              return response
          

          这种场景下,简单的数字验证码就够用了,用户体验也比较好。

          对于用户注册登录功能,需要平衡安全性和用户体验:

          # 使用更复杂的验证码,但不要太难
          class LoginCaptcha:
              def generate(self):
                  # 使用字母+数字,排除易混淆字符
                  chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
                  captcha_text = ''.join(random.choices(chars, k=4))
                  # 生成带干扰的验证码图片
                  # ...
          

          这种场景下,需要一定的安全性,但也不能太复杂影响用户体验。

          对于 API 接口,特别是发送短信、邮件等会产生费用的接口,需要更强的保护:

          • 使用商业方案或更复杂的验证码
          • 可以考虑滑动验证码、行为验证码等

          这种场景下,建议使用商业方案,或者实现更复杂的验证码逻辑。

          对于前后端分离的项目,需要返回 base64 格式的验证码:

          @app.route('/api/captcha')
          def get_captcha_api():
              image_data, text = generate_captcha()
              base64_data = base64.b64encode(image_data).decode()
              
              # 保存到 Redis(推荐)或 session
              redis_client.setex(f'captcha:{session_id}', 300, text)
              
              return {
                  'image': f'data:image/png;base64,{base64_data}',
                  'expires_in': 300
              }
          

          这种场景下,需要考虑验证码的存储和验证方式。

          选择验证码库时,需要根据项目需求来决定:

          快速开发:Django 项目用 django-simple-captcha,非 Django 项目用 captcha

          高安全性需求:考虑商业方案(极验、腾讯云验证码)。

          完全自定义:基于 PIL/Pillow + captcha 自行开发。

          最简单的起步方案

          # 最小化实现
          pip install captcha pillow
          
          # 生成验证码
          from captcha.image import ImageCaptcha
          
          image = ImageCaptcha()
          data = image.generate('1234')
          with open('captcha.png', 'wb') as f:
              f.write(data.getvalue())
          

          关键点总结:

          • 选择合适的库:根据项目框架和需求选择合适的库
          • 安全性考虑:添加过期时间、一次性使用、频率限制等
          • 用户体验:平衡安全性和用户体验,不要过度复杂
          • 生产环境:考虑日志记录、频率限制、前后端分离等

          希望这篇文章能帮助你选择合适的验证码库,并在实际项目中正确使用它们!

          下面是一个完整的 Flask 示例,展示了如何在实际项目中使用验证码:

          from flask import Flask, request, session, make_response, render_template_string
          from captcha.image import ImageCaptcha
          import random
          import time
          import io
          
          app = Flask(__name__)
          app.secret_key = 'your-secret-key-change-in-production'
          
          # HTML 模板
          HTML_TEMPLATE = """
          <!DOCTYPE html>
          <html>
          <head>
              <title>验证码示例</title>
              <style>
                  body {
                      font-family: Arial, sans-serif;
                      max-width: 500px;
                      margin: 50px auto;
                      padding: 20px;
                  }
                  .form-group {
                      margin-bottom: 15px;
                  }
                  label {
                      display: block;
                      margin-bottom: 5px;
                  }
                  input[type="text"], input[type="password"] {
                      width: 100%;
                      padding: 8px;
                      box-sizing: border-box;
                  }
                  .captcha-group {
                      display: flex;
                      align-items: center;
                      gap: 10px;
                  }
                  .captcha-img {
                      cursor: pointer;
                      border: 1px solid #ddd;
                      padding: 5px;
                  }
                  .refresh-link {
                      color: #007bff;
                      text-decoration: none;
                  }
                  .refresh-link:hover {
                      text-decoration: underline;
                  }
                  button {
                      background-color: #007bff;
                      color: white;
                      padding: 10px 20px;
                      border: none;
                      cursor: pointer;
                  }
                  .message {
                      margin-top: 10px;
                      padding: 10px;
                      border-radius: 4px;
                  }
                  .success {
                      background-color: #d4edda;
                      color: #155724;
                  }
                  .error {
                      background-color: #f8d7da;
                      color: #721c24;
                  }
              </style>
          </head>
          <body>
              <h2>登录示例</h2>
              <form method="POST" action="/login">
                  <div class="form-group">
                      <label>用户名:</label>
                      <input type="text" name="username" required>
                  </div>
                  <div class="form-group">
                      <label>密码:</label>
                      <input type="password" name="password" required>
                  </div>
                  <div class="form-group">
                      <label>验证码:</label>
                      <div class="captcha-group">
                          <input type="text" name="captcha" required style="flex: 1;">
                          <img id="captcha-img" class="captcha-img" 
                               src="/captcha" 
                               onclick="refreshCaptcha()" 
                               alt="验证码">
                          <a href="javascript:;" rel="external nofollow"  rel="external nofollow"  onclick="refreshCaptcha()" class="refresh-link">换一张</a>
                      </div>
                  </div>
                  <button type="submit">登录</button>
              </form>
              
              {% if message %}
              <div class="message {{ message_type }}">
                  {{ message }}
              </div>
              {% endif %}
              
              <script>
                  function refreshCaptcha() {
                      document.getElementById('captcha-img').src = '/captcha?' + Date.now();
                  }
              </script>
          </body>
          </html>
          """
          
          def generate_captcha_text(length=4):
              """生成验证码文本(排除易混淆字符)"""
              chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
              return ''.join(random.choices(chars, k=length))
          
          def generate_captcha():
              """生成验证码图片"""
              captcha_text = generate_captcha_text()
              
              # 创建验证码图像
              image = ImageCaptcha(width=120, height=40)
              data = image.generate(captcha_text)
              
              # 保存验证码到 session(带时间戳)
              session['captcha'] = captcha_text
              session['captcha_time'] = time.time()
              
              return data
          
          @app.route('/')
          def index():
              """首页"""
              return render_template_string(HTML_TEMPLATE)
          
          @app.route('/captcha')
          def get_captcha():
              """获取验证码图片"""
              image_data = generate_captcha()
              
              response = make_response(image_data.getvalue())
              response.headers['Content-Type'] = 'image/png'
              # 防止缓存
              response.headers['Cache-Control'] = 'no-cache, no-store, must-revalidate'
              response.headers['Pragma'] = 'no-cache'
              response.headers['Expires'] = '0'
              
              return response
          
          def verify_captcha(user_input, timeout=300):
              """验证验证码(带过期时间)"""
              if 'captcha' not in session or 'captcha_time' not in session:
                  return False, '验证码已过期,请刷新'
              
              # 检查是否过期(5分钟)
              if time.time() - session['captcha_time'] > timeout:
                  session.pop('captcha', None)
                  session.pop('captcha_time', None)
                  return False, '验证码已过期,请刷新'
              
              # 验证(忽略大小写)
              if user_input.upper() != session['captcha'].upper():
                  return False, '验证码错误'
              
              # 验证成功后清除验证码(一次性使用)
              session.pop('captcha', None)
              session.pop('captcha_time', None)
              
              return True, '验证成功'
          
          @app.route('/login', methods=['GET', 'POST'])
          def login():
              """登录处理"""
              if request.method == 'POST':
                  username = request.form.get('username', '')
                  password = request.form.get('password', '')
                  captcha_input = request.form.get('captcha', '')
                  
                  # 验证验证码
                  is_valid, message = verify_captcha(captcha_input)
                  
                  if not is_valid:
                      return render_template_string(
                          HTML_TEMPLATE,
                          message=message,
                          message_type='error'
                      )
                  
                  # 这里处理实际的登录逻辑
                  # 示例:简单的用户名密码验证
                  if username == 'admin' and password == '123456':
                      return render_template_string(
                          HTML_TEMPLATE,
                          message='登录成功!',
                          message_type='success'
                      )
                  else:
                      return render_template_string(
                          HTML_TEMPLATE,
                          message='用户名或密码错误',
                          message_type='error'
                      )
              
              return render_template_string(HTML_TEMPLATE)
          
          if __name__ == '__main__':
              app.run(debug=True)
          

          使用说明:

          1.安装依赖

          pip install flask captcha pillow
          

          2.运行应用

          python app.py
          

          3.访问应用:打开浏览器访问 http://localhost:5000

          4.测试登录

          • 用户名:admin
          • 密码:123456
          • 验证码:输入图片中显示的验证码

          这个 Demo 展示了:

          • 验证码生成:使用 captcha 库生成验证码图片
          • 验证码验证:带过期时间的一次性验证
          • 前端集成:点击图片或链接刷新验证码
          • 用户体验:清晰的错误提示和成功提示

          你可以根据实际需求修改和扩展这个示例。

          以上就是Python中三大主流图片验证码库使用推荐与实践指南的详细内容,更多关于Python图片验证码库的资料请关注风君子博客其它相关文章!

          您可能感兴趣的文章:

          • 使用 Python 和 LabelMe 实现图片验证码的自动标注功能
          • 利用Python实现生成并识别图片验证码
          • Python进行图片验证码识别方法步骤
          • 使用Python生成随机图片验证码的代码详解
          • Python中识别图片/滑块验证码准确率极高的ddddocr库详解
          • Python Flask实现图片验证码与邮箱验证码流程详细讲解
          • python3定位并识别图片验证码实现自动登录功能

          站内搜索