fastapi: 生成图形验证码
一,安装用到的第三方库
% pip install fastapi uvicorn captcha
二,代码
库
from captcha.image import ImageCaptcha
# 模拟 Redis 或 Session 存储,实际生产中应使用 Redis 并设置过期时间
captcha_store = {}
# 初始化验证码生成器
image_generator = ImageCaptcha(width=160, height=60)
调用:生成验证码图片
"""前台首页。"""
from fastapi import APIRouter, Depends
from app.core.captcha import captcha_store, image_generator
from app.core.response import success
import uuid
import random
import string
import base64
router = APIRouter(prefix="/capt",tags=["前台-首页"])
@router.get("/captcha")
def get_captcha():
"""生成图形验证码,直接以 JSON 形式返回 Base64 字符串和 ID"""
captcha_text = "".join(random.choices(string.ascii_uppercase + string.digits, k=4))
captcha_id = str(uuid.uuid4())
captcha_store[captcha_id] = captcha_text.lower()
# 1. 将生成的验证码图片写入内存缓冲区 (BytesIO)
img_buffer = image_generator.generate(captcha_text)
# 2. 将二进制数据转为 Base64 编码的字节,再解码为字符串
img_base64 = base64.b64encode(img_buffer.getvalue()).decode("utf-8")
# 3. 拼接成前端 <img> 标签可以直接识别的 Data URL 格式
captcha_image_url = f"data:image/png;base64,{img_base64}"
# 4. 直接返回标准的 JSON 对象
cont = {
"captcha_id": captcha_id,
"captcha_image": captcha_image_url
}
return success(cont)
校验
class LoginRequest(BaseModel):
username: str
password: str
captcha_id: str
captcha_code: str
@app.post("/api/login")
def login(data: LoginRequest):
if data.captcha_id not in captcha_store:
raise HTTPException(status_code=400, detail="验证码已过期,请刷新重试")
correct_code = captcha_store[data.captcha_id]
del captcha_store[data.captcha_id] # 及时销毁
if data.captcha_code.lower() != correct_code:
raise HTTPException(status_code=400, detail="验证码错误")
if data.username == "admin" and data.password == "123456":
return {"status": "success", "message": "登录成功!"}
raise HTTPException(status_code=400, detail="用户名或密码错误")
前端:
<script setup>
import { ref, reactive, onMounted } from 'vue';
import axios from 'axios';
const form = reactive({
username: '',
password: '',
captcha_id: '', // 用于和后端对暗号
captcha_code: '' // 用户输入的验证码文本
});
const captchaImage = ref(''); // 直接存储 Base64 字符串
// 获取/刷新图形验证码
const refreshCaptcha = async () => {
try {
// 像标准 API 一样直接 GET 请求 JSON 数据
const response = await axios.get('http://127.0.0');
// 直接从响应体(res.data)中取出 ID 和 Base64 图片
form.captcha_id = response.data.captcha_id;
captchaImage.value = response.data.captcha_image;
} catch (error) {
alert('获取验证码失败,请检查网络!');
}
};
const handleLogin = async () => {
try {
const res = await axios.post('http://127.0.0', form);
alert(res.data.message);
} catch (error) {
alert(error.response?.data?.detail || '登录失败');
form.captcha_code = '';
refreshCaptcha(); // 失败立即刷新
}
};
onMounted(() => {
refreshCaptcha();
});
</script>
html
<!-- 验证码图片展示区 -->
<img
v-if="captchaImage"
:src="captchaImage"
@click="refreshCaptcha"
title="点击刷新验证码"
class="captcha-img"
/>
<span v-else @click="refreshCaptcha" class="loading-text">加载中...</span>
三,测试效果

浙公网安备 33010602011771号