Python 图片验证码库推荐与实践指南


网罗开发 (小红书、快手、视频号同名)

大家好,我是 展菲,目前在上市企业从事人工智能项目研发管理工作,平时热衷于分享各种编程领域的软硬技能知识以及前沿技术,包括iOS、前端、Harmony OS、Java、Python等方向。在移动端开发、鸿蒙开发、物联网、嵌入式、云原生、开源等领域有深厚造诣。

图书作者:《ESP32-C3 物联网工程开发实战》
图书作者:《SwiftUI 入门,进阶与实战》
超级个体:COC上海社区主理人
特约讲师:大学讲师,谷歌亚马逊分享嘉宾
科技博主:华为HDE/HDG

我的博客内容涵盖广泛,主要分享技术教程、Bug解决方案、开发工具使用、前沿科技资讯、产品评测与使用体验 。我特别关注云服务产品评测、AI 产品对比、开发板性能测试以及技术报告,同时也会提供产品优缺点分析、横向对比,并分享技术沙龙与行业大会的参会体验。我的目标是为读者提供有深度、有实用价值的技术洞察与分析。

展菲:您的前沿技术领航员

👋 大家好,我是展菲!

📱 全网搜索"展菲",即可纵览我在各大平台的知识足迹。

📣 公众号"Swift社区",每周定时推送干货满满的技术长文,从新兴框架的剖析到运维实战的复盘,助您技术进阶之路畅通无阻。

💬 微信端添加好友"fzhanfei",与我直接交流,不管是项目瓶颈的求助,还是行业趋势的探讨,随时畅所欲言。

📅 最新动态:2025 年 3 月 17 日

快来加入技术社区,一起挖掘技术的无限潜能,携手迈向数字化新征程!

文章目录

前言

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

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

为什么需要验证码

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

常见的安全问题

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

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

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

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

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

开发中的痛点

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

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

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

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

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

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

主流图片验证码库推荐

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

captcha:Python 原生库,推荐度高

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

优点:

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

缺点:

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

适用场景:

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

基本使用:

python 复制代码
from captcha.image import ImageCaptcha

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

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

django-simple-captcha:Django 专属方案

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

优点:

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

缺点:

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

适用场景:

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

基本使用:

python 复制代码
# 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 转 Python 实现

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

优点:

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

缺点:

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

适用场景:

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

商业方案:滑动验证码和行为验证码

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

极验(geetest):

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

腾讯云验证码:

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

阿里云验证码:

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

适用场景:

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

Python 项目引入指南

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

基础安装配置

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

bash 复制代码
# 安装 captcha 库(Flask/FastAPI 通用)
pip install captcha pillow

# 安装 django-simple-captcha(Django 项目)
pip install django-simple-captcha

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

方案一:使用 captcha 库(Flask/FastAPI 通用)

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

python 复制代码
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

这个方案的关键点:

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

方案二:Django 项目集成 django-simple-captcha

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

第一步:配置 settings.py

python 复制代码
# settings.py
INSTALLED_APPS = [
    'captcha',
]

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

第二步:在 form 中使用

python 复制代码
# 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()

第三步:视图使用

python 复制代码
# 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})

第四步:模板中使用

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

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

方案三:高级自定义验证码

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

python 复制代码
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 分钟后自动失效:

python 复制代码
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 复制代码
<!-- 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:;" onclick="refreshCaptcha()">换一张</a>
    </div>
    <button type="submit">登录</button>
</form>

<script>
function refreshCaptcha() {
    // 通过添加时间戳参数强制刷新
    document.getElementById('captcha-img').src = '/captcha?' + Date.now();
}
</script>

关键点:

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

生产环境建议

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

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

python 复制代码
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 格式的验证码:

python 复制代码
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 项目,集成方便但灵活性有限。

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

实际应用场景

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

场景一:内部管理系统

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

python 复制代码
# 使用 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

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

场景二:用户注册登录

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

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

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

场景三:API 接口保护

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

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

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

场景四:前后端分离项目

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

python 复制代码
@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 自行开发。

最简单的起步方案

python 复制代码
# 最小化实现
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())

关键点总结:

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

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

完整可运行 Demo 代码

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

python 复制代码
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:;" 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. 安装依赖
bash 复制代码
pip install flask captcha pillow
  1. 运行应用
bash 复制代码
python app.py
  1. 访问应用

    打开浏览器访问 http://localhost:5000

  2. 测试登录

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

这个 Demo 展示了:

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

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

相关推荐
进击的小头2 小时前
C语言实现设计模式的核心基石
c语言·开发语言·设计模式
Yupureki2 小时前
《算法竞赛从入门到国奖》算法基础:入门篇-递归初阶
c语言·开发语言·数据结构·c++·算法·visual studio
有谁看见我的剑了?2 小时前
Python更换依赖包下载源
开发语言·python
Java程序员威哥2 小时前
云原生Java应用优化实战:资源限制+JVM参数调优,容器启动快50%
java·开发语言·jvm·python·docker·云原生
多多*2 小时前
程序设计工作室1月21日内部训练赛
java·开发语言·网络·jvm·tcp/ip
weixin_462446232 小时前
Python 实战:将 HTML 表格一键导出为 Excel(xlsx)
linux·python·excel·pandas
0思必得02 小时前
[Web自动化] Selenium浏览器对象属性
前端·python·selenium·自动化·web自动化
AI殉道师2 小时前
从0开发大模型之实现Agent(Bash到SKILL)
开发语言·bash
七夜zippoe2 小时前
NumPy向量化计算实战:从入门到精通的性能优化指南
python·性能优化·架构·numpy·广播机制·ufunc