实现一个动态验证码生成器:Canvas与JavaScript的完美结合
验证码(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创建一个功能完善的验证码生成器。通过随机字符、颜色、旋转角度以及干扰元素的组合,我们实现了一个既美观又具有一定安全性的验证码系统。这种前端验证码虽然不能替代服务器端的安全验证,但作为第一道防线,能有效阻止简单的自动化脚本攻击。
开发者可以根据实际需求进一步扩展功能,如增加更多安全特性或改进用户体验。希望这篇文章能帮助你理解验证码的实现原理,并在你的项目中应用这些技术。