How to Build a Custom CAPTCHA Service with Python Sanic
This tutorial shows how to generate a simple image‑based CAPTCHA using Python's Pillow library and the Sanic web framework, store the code in a session, and validate user input, with notes on adding asynchronous refresh functionality.
Dependencies required: sanic==19.9.0 and Pillow==7.0.0.
Verification code generation
import random
import string
import uuid
import base64
import platform
from PIL import Image, ImageDraw, ImageFont
from io import BytesIO
from sanic import Sanic
from sanic.response import HTTPResponse, text
from sanic.views import HTTPMethodView
app = Sanic()
session = {}
class VerifyCode:
def __init__(self, numbers: int):
"""Specify the number of characters to generate"""
self.number = numbers
def draw_lines(self, draw, num, width, height):
"""Draw interference lines"""
x1 = random.randint(0, width / 2)
y1 = random.randint(0, height / 2)
x2 = random.randint(0, width)
y2 = random.randint(height / 2, height)
draw.line(((x1, y1), (x2, y2)), fill='black', width=1)
def random_color(self):
"""Random color"""
return (random.randint(32, 127), random.randint(32, 127), random.randint(32, 127))
def gene_text(self):
"""Generate random verification text"""
return "".join(random.sample(string.ascii_letters + string.digits, self.number))
def get_verify_code(self):
"""Create image and code"""
code = self.gene_text()
width, height = 130, 30
im = Image.new("RGB", (width, height), "white")
sysstr = platform.system()
font = None
if sysstr == "Windows":
font = ImageFont.truetype("C:\\WINDOWS\\Fonts\\STXINGKA.TTF", 25)
elif sysstr == "Darwin":
font = ImageFont.truetype("/Library/Fonts/AppleMyungjo.ttf", 25)
draw = ImageDraw.Draw(im)
for item in range(self.number):
draw.text((5 + random.randint(-5,5) + 23*item,
5 + random.randint(-5,5)),
text=code[item],
fill=self.random_color(),
font=font)
self.draw_lines(draw, self.number, width, height)
return im, code
class SimpleView(HTTPMethodView):
body = """<html>...template omitted for brevity...</html>"""
async def get(self, request):
return self.response(error="")
async def post(self, request):
uuid = request.cookies.get("uuid", "1")
verfy_code = request.form.get("code", "2").lower()
code = session.get(uuid, "").lower()
if code == verfy_code:
return text('验证码正确')
return self.response(error='<input placeholder="验证码错误" disabled>')
def response(self, error):
im, code = VerifyCode(5).get_verify_code()
buf = BytesIO()
im.save(buf, "jpeg")
base64_data = base64.b64encode(buf.getvalue()).decode()
id = uuid.uuid1().__str__()
session[id] = code
body = self.body.format(base64_data=base64_data, error=error)
response = HTTPResponse(body, content_type="text/html; charset=utf-8")
response.cookies["uuid"] = id
return response
app.add_route(SimpleView.as_view(), '/code')
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8000)The implementation creates a simple CAPTCHA image, stores the generated code in a session dictionary, and validates user input; a refresh mechanism can be added by exposing an asynchronous endpoint that regenerates the image and updates the session key.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
MaGe Linux Operations
Founded in 2009, MaGe Education is a top Chinese high‑end IT training brand. Its graduates earn 12K+ RMB salaries, and the school has trained tens of thousands of students. It offers high‑pay courses in Linux cloud operations, Python full‑stack, automation, data analysis, AI, and Go high‑concurrency architecture. Thanks to quality courses and a solid reputation, it has talent partnerships with numerous internet firms.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
