最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Python中三大主流圖片驗(yàn)證碼庫使用推薦與實(shí)踐指南

 更新時(shí)間:2026年01月22日 09:19:48   作者:展菲  
相信很多 Python 開發(fā)者都遇到過類似的問題,項(xiàng)目需要驗(yàn)證碼功能,但不知道選哪個(gè)庫,也不知道怎么集成,今天我們就來聊聊 Python 中常用的圖片驗(yàn)證碼庫,以及如何在實(shí)際項(xiàng)目中應(yīng)用它們吧

前言

最近在做一個(gè) Web 項(xiàng)目的時(shí)候,需要添加驗(yàn)證碼功能來防止惡意注冊(cè)和破解。剛開始想著自己寫一個(gè)簡(jiǎn)單的驗(yàn)證碼生成器,但發(fā)現(xiàn)要考慮的東西還挺多的:圖片生成、字符扭曲、干擾線、過期時(shí)間、安全性等等。后來發(fā)現(xiàn)其實(shí)有很多現(xiàn)成的庫可以用,但選擇哪個(gè)庫、怎么集成到項(xiàng)目中,又是一個(gè)問題。

相信很多 Python 開發(fā)者都遇到過類似的問題:項(xiàng)目需要驗(yàn)證碼功能,但不知道選哪個(gè)庫,也不知道怎么集成。今天我們就來聊聊 Python 中常用的圖片驗(yàn)證碼庫,以及如何在實(shí)際項(xiàng)目中應(yīng)用它們。

為什么需要驗(yàn)證碼

在深入討論具體的庫之前,我們先聊聊為什么需要驗(yàn)證碼,以及在實(shí)際開發(fā)中會(huì)遇到哪些痛點(diǎn)。

常見的安全問題

現(xiàn)在的 Web 應(yīng)用面臨很多安全威脅,驗(yàn)證碼是其中一種重要的防護(hù)手段:

惡意注冊(cè):很多網(wǎng)站都會(huì)遇到惡意注冊(cè)的問題,有人用腳本批量注冊(cè)賬號(hào),占用服務(wù)器資源,甚至用來發(fā)送垃圾信息。如果沒有驗(yàn)證碼,這些腳本可以輕松地自動(dòng)化注冊(cè)流程。

惡意破解:對(duì)于登錄功能,如果沒有驗(yàn)證碼,攻擊者可以用腳本嘗試大量的用戶名密碼組合。雖然現(xiàn)在很多系統(tǒng)都有登錄失敗次數(shù)限制,但驗(yàn)證碼可以進(jìn)一步增加攻擊成本。

接口濫用:很多 API 接口如果沒有驗(yàn)證碼保護(hù),可能會(huì)被惡意調(diào)用,比如發(fā)送短信驗(yàn)證碼、發(fā)送郵件等。這些接口如果被濫用,不僅會(huì)消耗資源,還可能產(chǎn)生費(fèi)用。

爬蟲防護(hù):雖然驗(yàn)證碼不能完全阻止爬蟲,但可以增加爬蟲的成本。對(duì)于一些簡(jiǎn)單的爬蟲,驗(yàn)證碼就能起到很好的防護(hù)作用。

開發(fā)中的痛點(diǎn)

在實(shí)際開發(fā)中,實(shí)現(xiàn)驗(yàn)證碼功能會(huì)遇到很多痛點(diǎn):

圖片生成復(fù)雜:如果要自己實(shí)現(xiàn)驗(yàn)證碼生成,需要考慮很多細(xì)節(jié):字體選擇、字符扭曲、干擾線、干擾點(diǎn)、顏色搭配等等。這些細(xì)節(jié)處理不好,驗(yàn)證碼要么太簡(jiǎn)單容易被識(shí)別,要么太復(fù)雜用戶體驗(yàn)不好。

安全性問題:驗(yàn)證碼的安全性是一個(gè)大問題。如果驗(yàn)證碼太簡(jiǎn)單,容易被 OCR 識(shí)別;如果驗(yàn)證碼太復(fù)雜,用戶體驗(yàn)不好。而且還要考慮驗(yàn)證碼的過期時(shí)間、一次性使用、防止重放攻擊等問題。

框架集成:不同的 Web 框架(Flask、Django、FastAPI 等)集成驗(yàn)證碼的方式不一樣,需要針對(duì)性地適配。而且還要考慮前后端分離的場(chǎng)景,驗(yàn)證碼如何通過 API 返回。

用戶體驗(yàn):驗(yàn)證碼的用戶體驗(yàn)也很重要。如果驗(yàn)證碼看不清,用戶會(huì)抱怨;如果驗(yàn)證碼刷新不方便,用戶會(huì)煩躁。而且現(xiàn)在很多用戶習(xí)慣使用移動(dòng)端,驗(yàn)證碼在小屏幕上的顯示效果也要考慮。

維護(hù)成本:如果自己實(shí)現(xiàn)驗(yàn)證碼功能,后續(xù)的維護(hù)成本也不低。比如要更新字體、調(diào)整樣式、修復(fù) bug 等等。而使用現(xiàn)成的庫,可以降低維護(hù)成本。

主流圖片驗(yàn)證碼庫推薦

根據(jù)當(dāng)前的技術(shù)趨勢(shì),下面是最常用且好用的圖片驗(yàn)證碼庫,以及它們的特點(diǎn)和適用場(chǎng)景。

captcha:Python 原生庫,推薦度高

captcha 是一個(gè)由 Google 開發(fā)維護(hù)的 Python 庫,GitHub 上有 1.2k+ stars。它的特點(diǎn)是簡(jiǎn)單易用,支持自定義,適合各種 Python Web 框架。

優(yōu)點(diǎn):

  • 簡(jiǎn)單易用,API 設(shè)計(jì)清晰
  • 支持自定義圖片大小、字體、顏色等
  • 不依賴特定的 Web 框架,可以在 Flask、Django、FastAPI 等框架中使用
  • 由 Google 維護(hù),代碼質(zhì)量有保障

缺點(diǎn):

  • 功能相對(duì)簡(jiǎn)單,不支持復(fù)雜的驗(yàn)證碼樣式
  • 安全性相對(duì)較低,容易被 OCR 識(shí)別

適用場(chǎng)景:

  • 內(nèi)部系統(tǒng)或中小型項(xiàng)目
  • 對(duì)安全性要求不是特別高的場(chǎng)景
  • 需要快速集成驗(yàn)證碼功能的項(xiàng)目

基本使用:

from captcha.image import ImageCaptcha

# 創(chuàng)建驗(yàn)證碼圖像
image = ImageCaptcha(width=280, height=90)
data = image.generate('1234')
image.write('1234', 'out.png')

這個(gè)庫的使用非常簡(jiǎn)單,只需要幾行代碼就能生成驗(yàn)證碼圖片。但需要注意的是,它生成的驗(yàn)證碼相對(duì)簡(jiǎn)單,安全性不是特別高。

django-simple-captcha:Django 專屬方案

django-simple-captcha 是專門為 Django 框架設(shè)計(jì)的驗(yàn)證碼庫,GitHub 上有 1.6k+ stars。它的特點(diǎn)是 Django 集成度最高,開箱即用。

優(yōu)點(diǎn):

  • 與 Django 深度集成,使用非常方便
  • 支持 Django Forms,可以直接在表單中使用
  • 功能完善,支持多種驗(yàn)證碼樣式
  • 社區(qū)活躍,文檔完善

缺點(diǎn):

  • 僅限 Django 項(xiàng)目使用
  • 樣式相對(duì)固定,自定義程度有限

適用場(chǎng)景:

  • Django 項(xiàng)目
  • 需要快速集成驗(yàn)證碼功能的 Django 應(yīng)用
  • 不需要太多自定義的場(chǎng)景

基本使用:

# settings.py
INSTALLED_APPS = [
    'captcha',
]

# models.py
from django import forms
from captcha.fields import CaptchaField

class ContactForm(forms.Form):
    captcha = CaptchaField()

這個(gè)庫最大的優(yōu)勢(shì)就是與 Django 的集成非常好,如果你用的是 Django 框架,這個(gè)庫是最佳選擇。

kaptcha:Java 轉(zhuǎn) Python 實(shí)現(xiàn)

kaptcha 是模仿 Java 版 Kaptcha 的 Python 實(shí)現(xiàn),功能相對(duì)強(qiáng)大。

優(yōu)點(diǎn):

  • 功能強(qiáng)大,支持多種驗(yàn)證碼樣式
  • 可以生成復(fù)雜的驗(yàn)證碼圖片

缺點(diǎn):

  • 文檔相對(duì)較少
  • 社區(qū)活躍度不高
  • 使用相對(duì)復(fù)雜

適用場(chǎng)景:

  • 需要復(fù)雜驗(yàn)證碼樣式的項(xiàng)目
  • 對(duì) Java Kaptcha 熟悉的開發(fā)者

商業(yè)方案:滑動(dòng)驗(yàn)證碼和行為驗(yàn)證碼

除了開源的庫,還有一些商業(yè)方案,比如極驗(yàn)、騰訊云驗(yàn)證碼、阿里云驗(yàn)證碼等。這些方案通常提供滑動(dòng)驗(yàn)證碼、行為驗(yàn)證碼等更高級(jí)的驗(yàn)證方式。

極驗(yàn)(geetest):

  • 識(shí)別率高,安全性強(qiáng)
  • 支持多種驗(yàn)證方式(滑動(dòng)、點(diǎn)選、語音等)
  • 有免費(fèi)額度,超出后收費(fèi)

騰訊云驗(yàn)證碼:

  • 智能驗(yàn)證,多種形式
  • 與騰訊云服務(wù)集成
  • 按調(diào)用次數(shù)收費(fèi)

阿里云驗(yàn)證碼:

  • 風(fēng)險(xiǎn)識(shí)別,無感驗(yàn)證
  • 與阿里云服務(wù)集成
  • 按調(diào)用次數(shù)收費(fèi)

適用場(chǎng)景:

  • 對(duì)安全性要求很高的商業(yè)項(xiàng)目
  • 有預(yù)算支持的項(xiàng)目
  • 需要高級(jí)驗(yàn)證方式的場(chǎng)景

Python 項(xiàng)目引入指南

下面我們來看看如何在實(shí)際項(xiàng)目中引入和使用這些驗(yàn)證碼庫。

基礎(chǔ)安裝配置

首先,我們需要安裝相應(yīng)的庫:

# 安裝 captcha 庫(Flask/FastAPI 通用)
pip install captcha pillow

# 安裝 django-simple-captcha(Django 項(xiàng)目)
pip install django-simple-captcha

pillow 是 Python 的圖像處理庫,captcha 庫依賴它來生成圖片。如果你用的是 Django,還需要安裝 django-simple-captcha。

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

如果你用的是 Flask 或 FastAPI,可以使用 captcha 庫。下面是一個(gè)完整的 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():
    """生成驗(yàn)證碼"""
    # 生成隨機(jī)驗(yàn)證碼文本(排除易混淆字符)
    chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
    captcha_text = ''.join(random.choices(chars, k=4))
    
    # 創(chuàng)建驗(yàn)證碼圖像
    image = ImageCaptcha(width=120, height=40)
    data = image.generate(captcha_text)
    
    # 保存驗(yàn)證碼到 session
    session['captcha'] = captcha_text
    
    return data

@app.route('/captcha')
def get_captcha():
    """獲取驗(yàn)證碼圖片"""
    image_data = generate_captcha()
    
    response = make_response(image_data.getvalue())
    response.headers['Content-Type'] = 'image/png'
    # 防止緩存,確保每次請(qǐng)求都是新的驗(yàn)證碼
    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():
    """驗(yàn)證用戶輸入"""
    user_input = request.form.get('captcha', '').upper()
    server_captcha = session.get('captcha', '')
    
    if user_input == server_captcha:
        # 驗(yàn)證成功后清除驗(yàn)證碼,防止重復(fù)使用
        session.pop('captcha', None)
        return {'success': True, 'message': '驗(yàn)證碼正確'}
    else:
        return {'success': False, 'message': '驗(yàn)證碼錯(cuò)誤'}, 400

這個(gè)方案的關(guān)鍵點(diǎn):

  • 生成驗(yàn)證碼:使用 ImageCaptcha 生成圖片,并將驗(yàn)證碼文本保存到 session
  • 返回圖片:通過 HTTP 響應(yīng)返回圖片,并設(shè)置合適的響應(yīng)頭防止緩存
  • 驗(yàn)證輸入:從 session 中讀取驗(yàn)證碼,與用戶輸入進(jìn)行比較
  • 安全性:驗(yàn)證成功后清除 session 中的驗(yàn)證碼,防止重復(fù)使用

方案二:Django 項(xiàng)目集成 django-simple-captcha

如果你用的是 Django,使用 django-simple-captcha 會(huì)更方便:

第一步:配置 settings.py

# settings.py
INSTALLED_APPS = [
    'captcha',
]

# 驗(yàn)證碼設(shè)置
CAPTCHA_LENGTH = 4  # 字符數(shù)
CAPTCHA_TIMEOUT = 5  # 過期時(shí)間(分鐘)
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():
            # 驗(yàn)證通過,處理登錄邏輯
            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>

這個(gè)方案的優(yōu)勢(shì)是集成度非常高,Django 會(huì)自動(dòng)處理驗(yàn)證碼的生成、驗(yàn)證等邏輯,你只需要在表單中添加一個(gè)字段就行。

方案三:高級(jí)自定義驗(yàn)證碼

如果你需要更復(fù)雜的驗(yàn)證碼樣式,可以基于 PIL/Pillow 自己實(shí)現(xiàn):

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):
        """生成驗(yàn)證碼文本(排除易混淆字符)"""
        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):
        """創(chuàng)建驗(yàn)證碼圖像(添加干擾)"""
        # 創(chuàng)建畫布
        image = Image.new('RGB', (self.width, self.height), (255, 255, 255))
        draw = ImageDraw.Draw(image)
        
        # 添加隨機(jī)干擾點(diǎn)
        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))
        
        # 添加隨機(jī)干擾線
        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):
            # 每個(gè)字符隨機(jī)偏移
            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)
        
        # 轉(zhuǎn)換為字節(jié)流
        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):
        """生成隨機(jī)顏色"""
        return (random.randint(low, high), 
                random.randint(low, high), 
                random.randint(low, high))

這個(gè)方案的優(yōu)勢(shì)是可以完全自定義驗(yàn)證碼的樣式,但實(shí)現(xiàn)復(fù)雜度也更高。

最佳實(shí)踐建議

在實(shí)際項(xiàng)目中,除了基本的驗(yàn)證碼功能,我們還需要考慮很多細(xì)節(jié)。

安全性增強(qiáng)

添加過期時(shí)間:驗(yàn)證碼不應(yīng)該永久有效,應(yīng)該設(shè)置過期時(shí)間。比如 5 分鐘后自動(dòng)失效:

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:
        # 清理過期驗(yàn)證碼
        session.pop('captcha', None)
        session.pop('captcha_time', None)
        return False
    
    return user_input.upper() == session['captcha'].upper()

一次性使用:驗(yàn)證碼應(yīng)該是一次性的,驗(yàn)證成功后立即清除,防止重復(fù)使用。

大小寫不敏感:驗(yàn)證碼驗(yàn)證時(shí)應(yīng)該忽略大小寫,提升用戶體驗(yàn)。

防止重放攻擊:每次驗(yàn)證后都應(yīng)該清除驗(yàn)證碼,防止攻擊者重復(fù)使用同一個(gè)驗(yàn)證碼。

前端集成示例

前端集成驗(yàn)證碼時(shí),需要考慮用戶體驗(yàn):

<!-- HTML前端代碼 -->
<form id="login-form">
    <input type="text" name="username" placeholder="用戶名">
    <input type="password" name="password" placeholder="密碼">
    <div>
        <input type="text" name="captcha" placeholder="驗(yàn)證碼">
        <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() {
    // 通過添加時(shí)間戳參數(shù)強(qiáng)制刷新
    document.getElementById('captcha-img').src = '/captcha?' + Date.now();
}
</script>

關(guān)鍵點(diǎn):

  • 點(diǎn)擊圖片刷新:用戶可以點(diǎn)擊驗(yàn)證碼圖片來刷新
  • 換一張鏈接:提供明確的刷新入口
  • 防止緩存:通過添加時(shí)間戳參數(shù)防止瀏覽器緩存

生產(chǎn)環(huán)境建議

在生產(chǎn)環(huán)境中,我們還需要考慮更多問題:

頻率限制:對(duì)驗(yàn)證碼請(qǐng)求進(jìn)行 IP 限制,比如 60 秒內(nèi)最多 5 次。這樣可以防止惡意請(qǐng)求:

from flask import request
from functools import wraps
import time

# 簡(jiǎn)單的內(nèi)存緩存(生產(chǎn)環(huán)境建議用 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': '請(qǐng)求過于頻繁'}, 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():
    # ... 生成驗(yàn)證碼

驗(yàn)證碼多樣性:可以混合使用數(shù)字、字母、算術(shù)驗(yàn)證碼等,增加破解難度。

日志記錄:記錄驗(yàn)證失敗次數(shù),如果某個(gè) IP 連續(xù)失敗多次,可以臨時(shí)封禁。

前后端分離:如果前后端分離,API 可以返回 base64 格式的驗(yàn)證碼:

import base64

@app.route('/api/captcha')
def get_captcha_api():
    image_data, text = generate_captcha()
    base64_data = base64.b64encode(image_data.getvalue()).decode()
    
    # 保存驗(yàn)證碼到 session 或 Redis
    session['captcha'] = text
    
    return {
        'image': f'data:image/png;base64,{base64_data}',
        'expires_in': 300  # 過期時(shí)間(秒)
    }

CDN 緩存:靜態(tài)驗(yàn)證碼圖片可以考慮 CDN 緩存,但要注意防止緩存導(dǎo)致的問題。

商業(yè)方案對(duì)比

對(duì)于對(duì)安全性要求很高的商業(yè)項(xiàng)目,可以考慮使用商業(yè)驗(yàn)證碼方案。下面是幾個(gè)主流方案的對(duì)比:

方案優(yōu)點(diǎn)缺點(diǎn)適用場(chǎng)景
自建 captcha免費(fèi)、可控、無第三方依賴安全性較低、需自己維護(hù)內(nèi)部系統(tǒng)、中小項(xiàng)目
django-simple-captchaDjango 集成好、功能完善僅限 Django、樣式固定Django 項(xiàng)目
極驗(yàn)/騰訊云安全性高、智能驗(yàn)證、防破解收費(fèi)、第三方依賴對(duì)安全性要求高的商業(yè)項(xiàng)目

自建方案:適合內(nèi)部系統(tǒng)或中小型項(xiàng)目,成本低但安全性相對(duì)較低。

Django 方案:適合 Django 項(xiàng)目,集成方便但靈活性有限。

商業(yè)方案:適合對(duì)安全性要求很高的商業(yè)項(xiàng)目,安全性高但需要付費(fèi)。

實(shí)際應(yīng)用場(chǎng)景

讓我們看看幾個(gè)實(shí)際應(yīng)用場(chǎng)景,了解如何在不同情況下選擇合適的方案。

場(chǎng)景一:內(nèi)部管理系統(tǒng)

對(duì)于內(nèi)部管理系統(tǒng),對(duì)安全性要求不是特別高,可以選擇簡(jiǎn)單的方案:

# 使用 captcha 庫,簡(jiǎn)單快速
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

這種場(chǎng)景下,簡(jiǎn)單的數(shù)字驗(yàn)證碼就夠用了,用戶體驗(yàn)也比較好。

場(chǎng)景二:用戶注冊(cè)登錄

對(duì)于用戶注冊(cè)登錄功能,需要平衡安全性和用戶體驗(yàn):

# 使用更復(fù)雜的驗(yàn)證碼,但不要太難
class LoginCaptcha:
    def generate(self):
        # 使用字母+數(shù)字,排除易混淆字符
        chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
        captcha_text = ''.join(random.choices(chars, k=4))
        # 生成帶干擾的驗(yàn)證碼圖片
        # ...

這種場(chǎng)景下,需要一定的安全性,但也不能太復(fù)雜影響用戶體驗(yàn)。

場(chǎng)景三:API 接口保護(hù)

對(duì)于 API 接口,特別是發(fā)送短信、郵件等會(huì)產(chǎn)生費(fèi)用的接口,需要更強(qiáng)的保護(hù):

  • 使用商業(yè)方案或更復(fù)雜的驗(yàn)證碼
  • 可以考慮滑動(dòng)驗(yàn)證碼、行為驗(yàn)證碼等

這種場(chǎng)景下,建議使用商業(yè)方案,或者實(shí)現(xiàn)更復(fù)雜的驗(yàn)證碼邏輯。

場(chǎng)景四:前后端分離項(xiàng)目

對(duì)于前后端分離的項(xiàng)目,需要返回 base64 格式的驗(yàn)證碼:

@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
    }

這種場(chǎng)景下,需要考慮驗(yàn)證碼的存儲(chǔ)和驗(yàn)證方式。

總結(jié)

選擇驗(yàn)證碼庫時(shí),需要根據(jù)項(xiàng)目需求來決定:

快速開發(fā):Django 項(xiàng)目用 django-simple-captcha,非 Django 項(xiàng)目用 captcha。

高安全性需求:考慮商業(yè)方案(極驗(yàn)、騰訊云驗(yàn)證碼)。

完全自定義:基于 PIL/Pillow + captcha 自行開發(fā)。

最簡(jiǎn)單的起步方案

# 最小化實(shí)現(xiàn)
pip install captcha pillow

# 生成驗(yàn)證碼
from captcha.image import ImageCaptcha

image = ImageCaptcha()
data = image.generate('1234')
with open('captcha.png', 'wb') as f:
    f.write(data.getvalue())

關(guān)鍵點(diǎn)總結(jié):

  • 選擇合適的庫:根據(jù)項(xiàng)目框架和需求選擇合適的庫
  • 安全性考慮:添加過期時(shí)間、一次性使用、頻率限制等
  • 用戶體驗(yàn):平衡安全性和用戶體驗(yàn),不要過度復(fù)雜
  • 生產(chǎn)環(huán)境:考慮日志記錄、頻率限制、前后端分離等

希望這篇文章能幫助你選擇合適的驗(yàn)證碼庫,并在實(shí)際項(xiàng)目中正確使用它們!

完整可運(yùn)行 Demo 代碼

下面是一個(gè)完整的 Flask 示例,展示了如何在實(shí)際項(xiàng)目中使用驗(yàn)證碼:

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>驗(yàn)證碼示例</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>驗(yàn)證碼:</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="驗(yàn)證碼">
                <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):
    """生成驗(yàn)證碼文本(排除易混淆字符)"""
    chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
    return ''.join(random.choices(chars, k=length))

def generate_captcha():
    """生成驗(yàn)證碼圖片"""
    captcha_text = generate_captcha_text()
    
    # 創(chuàng)建驗(yàn)證碼圖像
    image = ImageCaptcha(width=120, height=40)
    data = image.generate(captcha_text)
    
    # 保存驗(yàn)證碼到 session(帶時(shí)間戳)
    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():
    """獲取驗(yàn)證碼圖片"""
    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):
    """驗(yàn)證驗(yàn)證碼(帶過期時(shí)間)"""
    if 'captcha' not in session or 'captcha_time' not in session:
        return False, '驗(yàn)證碼已過期,請(qǐng)刷新'
    
    # 檢查是否過期(5分鐘)
    if time.time() - session['captcha_time'] > timeout:
        session.pop('captcha', None)
        session.pop('captcha_time', None)
        return False, '驗(yàn)證碼已過期,請(qǐng)刷新'
    
    # 驗(yàn)證(忽略大小寫)
    if user_input.upper() != session['captcha'].upper():
        return False, '驗(yàn)證碼錯(cuò)誤'
    
    # 驗(yàn)證成功后清除驗(yàn)證碼(一次性使用)
    session.pop('captcha', None)
    session.pop('captcha_time', None)
    
    return True, '驗(yàn)證成功'

@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', '')
        
        # 驗(yàn)證驗(yàn)證碼
        is_valid, message = verify_captcha(captcha_input)
        
        if not is_valid:
            return render_template_string(
                HTML_TEMPLATE,
                message=message,
                message_type='error'
            )
        
        # 這里處理實(shí)際的登錄邏輯
        # 示例:簡(jiǎn)單的用戶名密碼驗(yàn)證
        if username == 'admin' and password == '123456':
            return render_template_string(
                HTML_TEMPLATE,
                message='登錄成功!',
                message_type='success'
            )
        else:
            return render_template_string(
                HTML_TEMPLATE,
                message='用戶名或密碼錯(cuò)誤',
                message_type='error'
            )
    
    return render_template_string(HTML_TEMPLATE)

if __name__ == '__main__':
    app.run(debug=True)

使用說明:

1.安裝依賴

pip install flask captcha pillow

2.運(yùn)行應(yīng)用

python app.py

3.訪問應(yīng)用:打開瀏覽器訪問 http://localhost:5000

4.測(cè)試登錄

  • 用戶名:admin
  • 密碼:123456
  • 驗(yàn)證碼:輸入圖片中顯示的驗(yàn)證碼

這個(gè) Demo 展示了:

  • 驗(yàn)證碼生成:使用 captcha 庫生成驗(yàn)證碼圖片
  • 驗(yàn)證碼驗(yàn)證:帶過期時(shí)間的一次性驗(yàn)證
  • 前端集成:點(diǎn)擊圖片或鏈接刷新驗(yàn)證碼
  • 用戶體驗(yàn):清晰的錯(cuò)誤提示和成功提示

你可以根據(jù)實(shí)際需求修改和擴(kuò)展這個(gè)示例。

以上就是Python中三大主流圖片驗(yàn)證碼庫使用推薦與實(shí)踐指南的詳細(xì)內(nèi)容,更多關(guān)于Python圖片驗(yàn)證碼庫的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • Python學(xué)習(xí)之pip包管理工具的使用

    Python學(xué)習(xí)之pip包管理工具的使用

    學(xué)習(xí)?Python?的過程中,經(jīng)常會(huì)使用?pip?命令去安裝第三方模塊。pip?是?Python?默認(rèn)集成的包管理工具,而其本質(zhì)就是?Python?標(biāo)準(zhǔn)庫中的一個(gè)包,只是比較特殊一些。本文就來為你你全面揭示一下?pip?包管理工具的使用
    2022-08-08
  • 基于Python List的賦值方法

    基于Python List的賦值方法

    今天小編就為大家分享一篇基于Python List的賦值方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-06-06
  • python實(shí)現(xiàn)隨機(jī)森林random forest的原理及方法

    python實(shí)現(xiàn)隨機(jī)森林random forest的原理及方法

    本篇文章主要介紹了python實(shí)現(xiàn)隨機(jī)森林random forest的原理及方法,詳細(xì)的介紹了隨機(jī)森林的原理和python實(shí)現(xiàn),非常具有參考價(jià)值,有興趣的可以了解一下
    2017-12-12
  • 一文詳解Python中的subprocess模塊

    一文詳解Python中的subprocess模塊

    subprocess模塊是Python標(biāo)準(zhǔn)庫的一部分,提供了一個(gè)跨平臺(tái)的方法來生成新進(jìn)程、連接其輸入/輸出/錯(cuò)誤管道,并獲取其返回碼,本文小編將和大家一起深入理解Python中的subprocess模塊,感興趣的小伙伴跟著小編一起來看看吧
    2024-08-08
  • Python3的urllib.parse常用函數(shù)小結(jié)(urlencode,quote,quote_plus,unquote,unquote_plus等)

    Python3的urllib.parse常用函數(shù)小結(jié)(urlencode,quote,quote_plus,unquot

    這篇文章主要介紹了Python3的urllib.parse常用函數(shù),結(jié)合實(shí)例形式分析了urlencode,quote,quote_plus,unquote,unquote_plus等函數(shù)的相關(guān)使用技巧,需要的朋友可以參考下
    2016-09-09
  • Python中字符串格式化str.format的詳細(xì)介紹

    Python中字符串格式化str.format的詳細(xì)介紹

    python從2.6開始支持format,新的更加容易讀懂的字符串格式化方法,下面這篇文章主要介紹了Python中字符串格式化str.format的相關(guān)資料,需要的朋友可以參考借鑒,下面來一起看看吧。
    2017-02-02
  • 淺談Tensorflow加載Vgg預(yù)訓(xùn)練模型的幾個(gè)注意事項(xiàng)

    淺談Tensorflow加載Vgg預(yù)訓(xùn)練模型的幾個(gè)注意事項(xiàng)

    這篇文章主要介紹了淺談Tensorflow加載Vgg預(yù)訓(xùn)練模型的幾個(gè)注意事項(xiàng)說明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2020-05-05
  • python題解LeetCode303區(qū)域和檢索示例詳解

    python題解LeetCode303區(qū)域和檢索示例詳解

    這篇文章主要為大家介紹了python題解LeetCode303區(qū)域和檢索示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • 利用python繪制二三維曲面和矢量流線圖的代碼示例

    利用python繪制二三維曲面和矢量流線圖的代碼示例

    這篇文章主要給大家詳細(xì)介紹了如何利用python繪制二三維曲面和矢量流線圖,文中通過代碼示例介紹的非常詳細(xì),對(duì)我們學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-07-07
  • 搞笑的程序猿:看看你是哪種Python程序員

    搞笑的程序猿:看看你是哪種Python程序員

    這篇文章主要介紹了搞笑的程序猿:看看你是哪種Python程序員,不久前,在互聯(lián)網(wǎng)上出現(xiàn)了一篇有趣的文章,講的是對(duì)于同一個(gè)問題,不同層次的Python程序員編出的Python代碼,顯示出了不同的風(fēng)格,代碼都很簡(jiǎn)單,有趣,需要的朋友可以參考下
    2015-06-06

最新評(píng)論

南安市| 郁南县| 乌审旗| 格尔木市| 合江县| 宣化县| 左贡县| 万全县| 同江市| 连州市| 左云县| 忻城县| 宝清县| 石阡县| 河源市| 方山县| 安塞县| 宜章县| 朝阳县| 章丘市| 山丹县| 鸡东县| 如皋市| 永川市| 内黄县| 澄城县| 南陵县| 神农架林区| 抚松县| 平度市| 炎陵县| 博爱县| 肇源县| 卢氏县| 始兴县| 通海县| 舒兰市| 清徐县| 南京市| 永清县| 孙吴县|