Python中三大主流圖片驗證碼庫使用推薦與實踐指南
前言
最近在做一個 Web 項目的時候,需要添加驗證碼功能來防止惡意注冊和破解。剛開始想著自己寫一個簡單的驗證碼生成器,但發(fā)現(xiàn)要考慮的東西還挺多的:圖片生成、字符扭曲、干擾線、過期時間、安全性等等。后來發(fā)現(xiàn)其實有很多現(xiàn)成的庫可以用,但選擇哪個庫、怎么集成到項目中,又是一個問題。
相信很多 Python 開發(fā)者都遇到過類似的問題:項目需要驗證碼功能,但不知道選哪個庫,也不知道怎么集成。今天我們就來聊聊 Python 中常用的圖片驗證碼庫,以及如何在實際項目中應(yīng)用它們。
為什么需要驗證碼
在深入討論具體的庫之前,我們先聊聊為什么需要驗證碼,以及在實際開發(fā)中會遇到哪些痛點。
常見的安全問題
現(xiàn)在的 Web 應(yīng)用面臨很多安全威脅,驗證碼是其中一種重要的防護手段:
惡意注冊:很多網(wǎng)站都會遇到惡意注冊的問題,有人用腳本批量注冊賬號,占用服務(wù)器資源,甚至用來發(fā)送垃圾信息。如果沒有驗證碼,這些腳本可以輕松地自動化注冊流程。
惡意破解:對于登錄功能,如果沒有驗證碼,攻擊者可以用腳本嘗試大量的用戶名密碼組合。雖然現(xiàn)在很多系統(tǒng)都有登錄失敗次數(shù)限制,但驗證碼可以進一步增加攻擊成本。
接口濫用:很多 API 接口如果沒有驗證碼保護,可能會被惡意調(diào)用,比如發(fā)送短信驗證碼、發(fā)送郵件等。這些接口如果被濫用,不僅會消耗資源,還可能產(chǎn)生費用。
爬蟲防護:雖然驗證碼不能完全阻止爬蟲,但可以增加爬蟲的成本。對于一些簡單的爬蟲,驗證碼就能起到很好的防護作用。
開發(fā)中的痛點
在實際開發(fā)中,實現(xiàn)驗證碼功能會遇到很多痛點:
圖片生成復(fù)雜:如果要自己實現(xiàn)驗證碼生成,需要考慮很多細節(jié):字體選擇、字符扭曲、干擾線、干擾點、顏色搭配等等。這些細節(jié)處理不好,驗證碼要么太簡單容易被識別,要么太復(fù)雜用戶體驗不好。
安全性問題:驗證碼的安全性是一個大問題。如果驗證碼太簡單,容易被 OCR 識別;如果驗證碼太復(fù)雜,用戶體驗不好。而且還要考慮驗證碼的過期時間、一次性使用、防止重放攻擊等問題。
框架集成:不同的 Web 框架(Flask、Django、FastAPI 等)集成驗證碼的方式不一樣,需要針對性地適配。而且還要考慮前后端分離的場景,驗證碼如何通過 API 返回。
用戶體驗:驗證碼的用戶體驗也很重要。如果驗證碼看不清,用戶會抱怨;如果驗證碼刷新不方便,用戶會煩躁。而且現(xiàn)在很多用戶習(xí)慣使用移動端,驗證碼在小屏幕上的顯示效果也要考慮。
維護成本:如果自己實現(xiàn)驗證碼功能,后續(xù)的維護成本也不低。比如要更新字體、調(diào)整樣式、修復(fù) bug 等等。而使用現(xiàn)成的庫,可以降低維護成本。
主流圖片驗證碼庫推薦
根據(jù)當前的技術(shù)趨勢,下面是最常用且好用的圖片驗證碼庫,以及它們的特點和適用場景。
captcha:Python 原生庫,推薦度高
captcha 是一個由 Google 開發(fā)維護的 Python 庫,GitHub 上有 1.2k+ stars。它的特點是簡單易用,支持自定義,適合各種 Python Web 框架。
優(yōu)點:
- 簡單易用,API 設(shè)計清晰
- 支持自定義圖片大小、字體、顏色等
- 不依賴特定的 Web 框架,可以在 Flask、Django、FastAPI 等框架中使用
- 由 Google 維護,代碼質(zhì)量有保障
缺點:
- 功能相對簡單,不支持復(fù)雜的驗證碼樣式
- 安全性相對較低,容易被 OCR 識別
適用場景:
- 內(nèi)部系統(tǒng)或中小型項目
- 對安全性要求不是特別高的場景
- 需要快速集成驗證碼功能的項目
基本使用:
from captcha.image import ImageCaptcha
# 創(chuàng)建驗證碼圖像
image = ImageCaptcha(width=280, height=90)
data = image.generate('1234')
image.write('1234', 'out.png')
這個庫的使用非常簡單,只需要幾行代碼就能生成驗證碼圖片。但需要注意的是,它生成的驗證碼相對簡單,安全性不是特別高。
django-simple-captcha:Django 專屬方案
django-simple-captcha 是專門為 Django 框架設(shè)計的驗證碼庫,GitHub 上有 1.6k+ stars。它的特點是 Django 集成度最高,開箱即用。
優(yōu)點:
- 與 Django 深度集成,使用非常方便
- 支持 Django Forms,可以直接在表單中使用
- 功能完善,支持多種驗證碼樣式
- 社區(qū)活躍,文檔完善
缺點:
- 僅限 Django 項目使用
- 樣式相對固定,自定義程度有限
適用場景:
- Django 項目
- 需要快速集成驗證碼功能的 Django 應(yīng)用
- 不需要太多自定義的場景
基本使用:
# settings.py
INSTALLED_APPS = [
'captcha',
]
# models.py
from django import forms
from captcha.fields import CaptchaField
class ContactForm(forms.Form):
captcha = CaptchaField()
這個庫最大的優(yōu)勢就是與 Django 的集成非常好,如果你用的是 Django 框架,這個庫是最佳選擇。
kaptcha:Java 轉(zhuǎn) Python 實現(xiàn)
kaptcha 是模仿 Java 版 Kaptcha 的 Python 實現(xiàn),功能相對強大。
優(yōu)點:
- 功能強大,支持多種驗證碼樣式
- 可以生成復(fù)雜的驗證碼圖片
缺點:
- 文檔相對較少
- 社區(qū)活躍度不高
- 使用相對復(fù)雜
適用場景:
- 需要復(fù)雜驗證碼樣式的項目
- 對 Java Kaptcha 熟悉的開發(fā)者
商業(yè)方案:滑動驗證碼和行為驗證碼
除了開源的庫,還有一些商業(yè)方案,比如極驗、騰訊云驗證碼、阿里云驗證碼等。這些方案通常提供滑動驗證碼、行為驗證碼等更高級的驗證方式。
極驗(geetest):
- 識別率高,安全性強
- 支持多種驗證方式(滑動、點選、語音等)
- 有免費額度,超出后收費
騰訊云驗證碼:
- 智能驗證,多種形式
- 與騰訊云服務(wù)集成
- 按調(diào)用次數(shù)收費
阿里云驗證碼:
- 風險識別,無感驗證
- 與阿里云服務(wù)集成
- 按調(diào)用次數(shù)收費
適用場景:
- 對安全性要求很高的商業(yè)項目
- 有預(yù)算支持的項目
- 需要高級驗證方式的場景
Python 項目引入指南
下面我們來看看如何在實際項目中引入和使用這些驗證碼庫。
基礎(chǔ)安裝配置
首先,我們需要安裝相應(yīng)的庫:
# 安裝 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 示例:
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))
# 創(chuàng)建驗證碼圖像
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:
# 驗證成功后清除驗證碼,防止重復(fù)使用
session.pop('captcha', None)
return {'success': True, 'message': '驗證碼正確'}
else:
return {'success': False, 'message': '驗證碼錯誤'}, 400
這個方案的關(guān)鍵點:
- 生成驗證碼:使用
ImageCaptcha生成圖片,并將驗證碼文本保存到 session - 返回圖片:通過 HTTP 響應(yīng)返回圖片,并設(shè)置合適的響應(yīng)頭防止緩存
- 驗證輸入:從 session 中讀取驗證碼,與用戶輸入進行比較
- 安全性:驗證成功后清除 session 中的驗證碼,防止重復(fù)使用
方案二:Django 項目集成 django-simple-captcha
如果你用的是 Django,使用 django-simple-captcha 會更方便:
第一步:配置 settings.py
# settings.py
INSTALLED_APPS = [
'captcha',
]
# 驗證碼設(shè)置
CAPTCHA_LENGTH = 4 # 字符數(shù)
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>
這個方案的優(yōu)勢是集成度非常高,Django 會自動處理驗證碼的生成、驗證等邏輯,你只需要在表單中添加一個字段就行。
方案三:高級自定義驗證碼
如果你需要更復(fù)雜的驗證碼樣式,可以基于 PIL/Pillow 自己實現(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):
"""生成驗證碼文本(排除易混淆字符)"""
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)建驗證碼圖像(添加干擾)"""
# 創(chuàng)建畫布
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)
# 轉(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):
"""生成隨機顏色"""
return (random.randint(low, high),
random.randint(low, high),
random.randint(low, high))
這個方案的優(yōu)勢是可以完全自定義驗證碼的樣式,但實現(xiàn)復(fù)雜度也更高。
最佳實踐建議
在實際項目中,除了基本的驗證碼功能,我們還需要考慮很多細節(jié)。
安全性增強
添加過期時間:驗證碼不應(yīng)該永久有效,應(yīng)該設(shè)置過期時間。比如 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()
一次性使用:驗證碼應(yīng)該是一次性的,驗證成功后立即清除,防止重復(fù)使用。
大小寫不敏感:驗證碼驗證時應(yīng)該忽略大小寫,提升用戶體驗。
防止重放攻擊:每次驗證后都應(yīng)該清除驗證碼,防止攻擊者重復(fù)使用同一個驗證碼。
前端集成示例
前端集成驗證碼時,需要考慮用戶體驗:
<!-- 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() {
// 通過添加時間戳參數(shù)強制刷新
document.getElementById('captcha-img').src = '/captcha?' + Date.now();
}
</script>
關(guān)鍵點:
- 點擊圖片刷新:用戶可以點擊驗證碼圖片來刷新
- 換一張鏈接:提供明確的刷新入口
- 防止緩存:通過添加時間戳參數(shù)防止瀏覽器緩存
生產(chǎn)環(huán)境建議
在生產(chǎn)環(huán)境中,我們還需要考慮更多問題:
頻率限制:對驗證碼請求進行 IP 限制,比如 60 秒內(nèi)最多 5 次。這樣可以防止惡意請求:
from flask import request
from functools import wraps
import time
# 簡單的內(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': '請求過于頻繁'}, 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():
# ... 生成驗證碼
驗證碼多樣性:可以混合使用數(shù)字、字母、算術(shù)驗證碼等,增加破解難度。
日志記錄:記錄驗證失敗次數(shù),如果某個 IP 連續(xù)失敗多次,可以臨時封禁。
前后端分離:如果前后端分離,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 緩存:靜態(tài)驗證碼圖片可以考慮 CDN 緩存,但要注意防止緩存導(dǎo)致的問題。
商業(yè)方案對比
對于對安全性要求很高的商業(yè)項目,可以考慮使用商業(yè)驗證碼方案。下面是幾個主流方案的對比:
| 方案 | 優(yōu)點 | 缺點 | 適用場景 |
|---|---|---|---|
| 自建 captcha | 免費、可控、無第三方依賴 | 安全性較低、需自己維護 | 內(nèi)部系統(tǒng)、中小項目 |
| django-simple-captcha | Django 集成好、功能完善 | 僅限 Django、樣式固定 | Django 項目 |
| 極驗/騰訊云 | 安全性高、智能驗證、防破解 | 收費、第三方依賴 | 對安全性要求高的商業(yè)項目 |
自建方案:適合內(nèi)部系統(tǒng)或中小型項目,成本低但安全性相對較低。
Django 方案:適合 Django 項目,集成方便但靈活性有限。
商業(yè)方案:適合對安全性要求很高的商業(yè)項目,安全性高但需要付費。
實際應(yīng)用場景
讓我們看看幾個實際應(yīng)用場景,了解如何在不同情況下選擇合適的方案。
場景一:內(nèi)部管理系統(tǒng)
對于內(nèi)部管理系統(tǒng),對安全性要求不是特別高,可以選擇簡單的方案:
# 使用 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
這種場景下,簡單的數(shù)字驗證碼就夠用了,用戶體驗也比較好。
場景二:用戶注冊登錄
對于用戶注冊登錄功能,需要平衡安全性和用戶體驗:
# 使用更復(fù)雜的驗證碼,但不要太難
class LoginCaptcha:
def generate(self):
# 使用字母+數(shù)字,排除易混淆字符
chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789'
captcha_text = ''.join(random.choices(chars, k=4))
# 生成帶干擾的驗證碼圖片
# ...
這種場景下,需要一定的安全性,但也不能太復(fù)雜影響用戶體驗。
場景三:API 接口保護
對于 API 接口,特別是發(fā)送短信、郵件等會產(chǎn)生費用的接口,需要更強的保護:
- 使用商業(yè)方案或更復(fù)雜的驗證碼
- 可以考慮滑動驗證碼、行為驗證碼等
這種場景下,建議使用商業(yè)方案,或者實現(xiàn)更復(fù)雜的驗證碼邏輯。
場景四:前后端分離項目
對于前后端分離的項目,需要返回 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
}
這種場景下,需要考慮驗證碼的存儲和驗證方式。
總結(jié)
選擇驗證碼庫時,需要根據(jù)項目需求來決定:
快速開發(fā):Django 項目用 django-simple-captcha,非 Django 項目用 captcha。
高安全性需求:考慮商業(yè)方案(極驗、騰訊云驗證碼)。
完全自定義:基于 PIL/Pillow + captcha 自行開發(fā)。
最簡單的起步方案:
# 最小化實現(xiàn)
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())
關(guān)鍵點總結(jié):
- 選擇合適的庫:根據(jù)項目框架和需求選擇合適的庫
- 安全性考慮:添加過期時間、一次性使用、頻率限制等
- 用戶體驗:平衡安全性和用戶體驗,不要過度復(fù)雜
- 生產(chǎn)環(huán)境:考慮日志記錄、頻率限制、前后端分離等
希望這篇文章能幫助你選擇合適的驗證碼庫,并在實際項目中正確使用它們!
完整可運行 Demo 代碼
下面是一個完整的 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()
# 創(chuàng)建驗證碼圖像
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.運行應(yīng)用:
python app.py
3.訪問應(yīng)用:打開瀏覽器訪問 http://localhost:5000
4.測試登錄:
- 用戶名:
admin - 密碼:
123456 - 驗證碼:輸入圖片中顯示的驗證碼
這個 Demo 展示了:
- 驗證碼生成:使用
captcha庫生成驗證碼圖片 - 驗證碼驗證:帶過期時間的一次性驗證
- 前端集成:點擊圖片或鏈接刷新驗證碼
- 用戶體驗:清晰的錯誤提示和成功提示
你可以根據(jù)實際需求修改和擴展這個示例。
以上就是Python中三大主流圖片驗證碼庫使用推薦與實踐指南的詳細內(nèi)容,更多關(guān)于Python圖片驗證碼庫的資料請關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
python第三方包安裝路徑site-packages下.libs作用詳解
這篇文章主要為大家介紹了python?第三方包安裝路徑?site-packages?下面的以?.libs?結(jié)尾的路徑作用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2023-09-09
python lambda表達式(匿名函數(shù))寫法解析
這篇文章主要介紹了python lambda表達式(匿名函數(shù))寫法解析,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-09-09
Python3 pyecharts 模塊數(shù)據(jù)可視化的高效利器(實戰(zhàn)案例)
pyecharts作為Python 生態(tài)中一款優(yōu)秀的數(shù)據(jù)可視化庫,以其簡潔的 API 設(shè)計、豐富的圖表類型和良好的交互性,成為開發(fā)者快速實現(xiàn)數(shù)據(jù)可視化的首選工具之一,本文將從核心特性、基礎(chǔ)使用流程、高級功能及實戰(zhàn)案例等方面,全面解析pyecharts,感興趣的朋友跟隨小編一起看看吧2025-10-10
python導(dǎo)入導(dǎo)出redis數(shù)據(jù)的實現(xiàn)
本文主要介紹了python導(dǎo)入導(dǎo)出redis數(shù)據(jù)的實現(xiàn),文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2022-02-02
解決ToPILImage時出現(xiàn)維度報錯問題pic should be 2/3 d
這篇文章主要介紹了解決ToPILImage時出現(xiàn)維度報錯問題pic should be 2/3 dimensional. Got 4 dimensions.具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2024-02-02

