验证码(CAPTCHA)是现代网站中常见的安全机制,用于区分人类用户和自动化程序。本文将详细介绍如何使用HTML5 Canvas和JavaScript创建一个美观且功能完整的验证码生成器。
一、核心功能概述
这个验证码生成器具有以下特点:
-
随机生成4位字母数字组合(区分大小写)
-
每个字符随机旋转一定角度增加识别难度
-
随机颜色字符增强视觉效果
-
添加干扰线和干扰点防止OCR识别
-
点击验证码可刷新生成新验证码
-
将生成的验证码值存储在DOM属性中便于验证
二、HTML结构
首先需要一个简单的HTML结构作为基础:
<canvas id="canvas" width="120" height="40"></canvas>
这个canvas元素将作为我们绘制验证码的画布。
三、JavaScript实现解析
1. 初始化与事件绑定
$(function () {code_draw();// 点击后刷新验证码$("#canvas").on('click', function () {code_draw();});
});
这段代码在文档加载完成后:
-
立即调用
code_draw()
函数生成初始验证码 -
为canvas元素绑定点击事件,点击时重新生成验证码
2. 验证码绘制主函数
code_draw()
函数是核心功能所在:
function code_draw() {// 获取canvas尺寸var canvas_width = $('#canvas').width();var canvas_height = $('#canvas').height();// 获取canvas上下文var canvas = document.getElementById("canvas");var context = canvas.getContext("2d");// 设置canvas尺寸(重要!防止缩放导致的模糊)canvas.width = canvas_width;canvas.height = canvas_height;// 定义验证码字符集var sCode = "A,B,C,E,F,G,H,J,K,L,M,N,P,Q,R,S,T,W,X,Y,Z,1,2,3,4,5,6,7,8,9,0";var aCode = sCode.split(",");var aLength = aCode.length;// 存储生成的验证码值var value = [];// 绘制4个随机字符for (var i = 0; i <= 3; i++) {var j = Math.floor(Math.random() * aLength); // 随机索引var deg = Math.random() * 30 * Math.PI / 180; // 随机旋转角度(弧度制)var txt = aCode[j]; // 获取随机字符value[i] = txt.toLowerCase(); // 存储小写形式(便于后续验证不区分大小写)// 字符位置计算var x = 10 + i * 20;var y = 20 + Math.random() * 8;// 设置字体样式context.font = "bold 23px 微软雅黑";// 变换坐标系实现旋转context.translate(x, y);context.rotate(deg);// 绘制文字context.fillStyle = code_randomColor();context.fillText(txt, 0, 0);// 恢复坐标系context.rotate(-deg);context.translate(-x, -y);}// 将验证码值存储到data属性value = value.join("");$('#canvas').attr('data-code', value);// 绘制干扰线for (var i = 0; i <= 5; i++) {context.strokeStyle = code_randomColor();context.beginPath();context.moveTo(Math.random() * canvas_width, Math.random() * canvas_height);context.lineTo(Math.random() * canvas_width, Math.random() * canvas_height);context.stroke();}// 绘制干扰点for (var i = 0; i <= 30; i++) {context.strokeStyle = code_randomColor();context.beginPath();var x = Math.random() * canvas_width;var y = Math.random() * canvas_height;context.moveTo(x, y);context.lineTo(x + 1, y + 1);context.stroke();}
}
3. 随机颜色生成
function code_randomColor() {var r = Math.floor(Math.random() * 256);var g = Math.floor(Math.random() * 256);var b = Math.floor(Math.random() * 256);return "rgb(" + r + "," + g + "," + b + ")";
}
这个辅助函数生成随机的RGB颜色值,用于字符、干扰线和干扰点的着色。
四、关键技术点解析
-
Canvas坐标系变换:
-
使用
translate()
和rotate()
实现字符的随机旋转 -
注意在绘制完一个字符后需要恢复坐标系状态
-
-
防模糊处理:
-
通过设置
canvas.width
和canvas.height
而不仅仅是CSS尺寸,确保在高DPI设备上清晰显示
-
-
验证码存储:
-
将生成的验证码值存储在canvas的
data-code
属性中,便于后续验证时获取
-
-
安全增强:
-
干扰线和干扰点的随机分布有效防止简单的图像识别
-
字符随机旋转增加机器识别难度
-
五、实际应用与验证
在实际使用时,可以将用户输入与canvas的data-code属性值进行比较:
function validateCode(input) {var canvasCode = $('#canvas').attr('data-code').toLowerCase();return input.toLowerCase() === canvasCode;
}
六、优化建议
-
增加字符间距随机性:当前字符间距固定为20px,可以增加随机性
-
更多字体变化:可以引入多种字体随机选择
-
背景色随机:为canvas添加随机背景色增强视觉效果
-
扭曲变形:对字符进行更复杂的变形处理
-
响应式设计:根据容器大小自动调整验证码尺寸
七、完整代码示例
<!DOCTYPE html>
<html>
<head><title>验证码示例</title><script src="https://code.jquery.com/jquery-3.6.0.min.js"></script><style>#canvas {border: 1px solid #ddd;cursor: pointer;}</style>
</head>
<body><canvas id="canvas" width="120" height="40"></canvas><script>$(function () {code_draw();// 点击后刷新验证码$("#canvas").on('click', function () {code_draw();});});function code_draw() {var canvas_width = $('#canvas').width();var canvas_height = $('#canvas').height();var canvas = document.getElementById("canvas");var context = canvas.getContext("2d");canvas.width = canvas_width;canvas.height = canvas_height;var sCode = "A,B,C,E,F,G,H,J,K,L,M,N,P,Q,R,S,T,W,X,Y,Z,1,2,3,4,5,6,7,8,9,0";var aCode = sCode.split(",");var aLength = aCode.length;var value = [];for (var i = 0; i <= 3; i++) {var j = Math.floor(Math.random() * aLength);var deg = Math.random() * 30 * Math.PI / 180;var txt = aCode[j];value[i] = txt.toLowerCase();var x = 10 + i * 20;var y = 20 + Math.random() * 8;context.font = "bold 23px 微软雅黑";context.translate(x, y);context.rotate(deg);context.fillStyle = code_randomColor();context.fillText(txt, 0, 0);context.rotate(-deg);context.translate(-x, -y);}value = value.join("");$('#canvas').attr('data-code', value);for (var i = 0; i <= 5; i++) {context.strokeStyle = code_randomColor();context.beginPath();context.moveTo(Math.random() * canvas_width, Math.random() * canvas_height);context.lineTo(Math.random() * canvas_width, Math.random() * canvas_height);context.stroke();}for (var i = 0; i <= 30; i++) {context.strokeStyle = code_randomColor();context.beginPath();var x = Math.random() * canvas_width;var y = Math.random() * canvas_height;context.moveTo(x, y);context.lineTo(x + 1, y + 1);context.stroke();}}function code_randomColor() {var r = Math.floor(Math.random() * 256);var g = Math.floor(Math.random() * 256);var b = Math.floor(Math.random() * 256);return "rgb(" + r + "," + g + "," + b + ")";}</script>
</body>
</html>
八、总结
本文详细介绍了如何使用Canvas和JavaScript创建一个功能完善的验证码生成器。通过随机字符、颜色、旋转角度以及干扰元素的组合,我们实现了一个既美观又具有一定安全性的验证码系统。这种前端验证码虽然不能替代服务器端的安全验证,但作为第一道防线,能有效阻止简单的自动化脚本攻击。
开发者可以根据实际需求进一步扩展功能,如增加更多安全特性或改进用户体验。希望这篇文章能帮助你理解验证码的实现原理,并在你的项目中应用这些技术。