校验码一定要后端生成吗?web前端生成验证码
需求场景描述
在登录界面,常常看到先要看图识别验证码,然后填写验证码和账号密码才能登录。有些短信发送功能,在发送前也会要求先识别一个验证码。当然这个验证操作,可能是看图识别4-6验证码并填写正确,也可能是现在比较流行的看图划动滑块验证条,滑到一定的位置重合,则表示验证成功。那么这些常见验证操作主要作用是什么呢?
此外,以前的项目大多是后端生成验证码的图片返回给前端,个人认为前端生成这样的图形识别验证码或验证滑块,同样具有验证意义,也可以起到防范机器保护系统的作用。
检验码的作用与意义
1.有效防止机器疯狂利用碰撞原理,去猜测破解系统,有效防止机器人自动注册、登录、灌水。 2.图片验证码的方式,实现成本低,效果明显。 3.必要性上,即使这给用户带来一定的麻烦,从安全和防护作用上看,十分有必要。 4.登陆前做些必要的校验验证工作,已经形成了共识。
关键技术点介绍:canvas
1.认识 canvas
Canvas API 提供了一个通过JavaScript 和 HTML的元素来绘制图形的方式。它可以用于动画、游戏画面、数据可视化、图片编辑以及实时视频处理等方面。
Canvas API主要聚焦于2D图形。而同样使用元素的 WebGL API 则用于绘制硬件加速的2D和3D图形。
2.浏览器兼容性
Mozilla 程序从 Gecko 1.8 (Firefox 1.5) 开始支持 。它首先是由 Apple 引入的,用于 OS X Dashboard 和 Safari。Internet Explorer 从IE9开始支持 ,更旧版本的IE中,页面可以通过引入 Google 的 Explorer Canvas 项目中的脚本来获得支持。Google Chrome和Opera 9+ 也支持 。
完整 Demo 示例
1.Demo效果图
2.完整 Demo代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>web前端生成校验码</title>
</head>
<style>
canvas {
width: 100%;
height: 100%;
}
#codeImg {
cursor: pointer;
vertical-align: top;
}
#reset {
cursor: pointer;
}
</style>
<body>
<h1>前端 js 生产验证码</h1>
<div>
<div style="margin-bottom: 20px">
<img id="codeImg" class="code" onclick="showCode()" alt="校验码图" />
<span id="reset" onclick="showCode()">看不清换一张</span>
</div>
<div>
<span>验证码:</span>
<input type="text" id="inputCode" />
</div>
<div style="margin-bottom: 20px">
<button onclick="validateCode()">确定</button>
</div>
</div>
<script>
// 页面加载完成时,生成随机验证码
window.onload = function() {
showCode();
};
// 窗口大小调整时,重新生成校验码
window.onresize = function() {
showCode();
};
// 展示验证码:将验证码赋值到dom的image上
function showCode() {
let image = document.getElementById("codeImg");
let obj = drawCode();
image.src = obj.base64;
console.log("showCode");
console.log(obj.text);
window.sessionStorage.setItem("text", obj.text);
}
// 校验验证码的正确性
function validateCode() {
let inputCode = document.getElementById("inputCode").value.toUpperCase();
let text = window.sessionStorage.getItem("text").toUpperCase();
if (inputCode === text) {
alert("正确");
} else {
alert("错误");
}
}
// 绘制验证码
function drawCode() {
// 校验码的组成库,我们去掉了大小写的字母Oo,因为有0了。
let nums = ["1", "2", "3", "4", "5", "6", "7", "8", "9", "0",
"A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L",
"M", "N", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z",
"a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m",
"n", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"
],
text = "";
// 创建 canvas 画布,并设置宽高
let canvas = document.createElement("canvas");
canvas.width = 98;
canvas.height = 45;
// 获取画布2D上下文
let context = canvas.getContext("2d");
// 画布填充色
context.fillStyle = "#00BEFD";
// 清空画布
context.fillRect(0, 0, canvas.width, canvas.height);
// 设置字体颜色
context.fillStyle = "white";
// 设置字体
context.font = "25px Microsoft YaHei";
let rand = [], x = [], y = [];
// 绘制校验码到画布上
for (let i = 0; i < 4; i++) {
rand.push(rand[i]);
rand[i] = nums[Math.floor(Math.random() * nums.length)];
x[i] = i * 20 + 10;
y[i] = Math.random() * 20 + 20;
context.fillText(rand[i], x[i], y[i]);
}
// 画2条随机线,可以根据需要增减,画随机线主要是为了提高识别难度,防范机器识别
for (let i = 0; i < 2; i++) {
drawline(canvas, context);
}
// 画20个随机点,随机点的意义同随即线
for (let i = 0; i < 20; i++) {
drawDot(canvas, context);
}
// canvas 生成 image
let base64 = convertCanvasToImage(canvas);
// 校验码的值,将字符串转换为大写,用户填写的校验码不区分大小写
text = rand.join("").toUpperCase();
return { base64: base64, text: text };
}
// 画随机线函数
function drawline(canvas, context) {
// 随机线的起点x坐标是画布x坐标0位置,y坐标是画布高度的随机数
context.moveTo(Math.floor(Math.random() * canvas.width), Math.floor(Math.random() * canvas.height));
// 随机线的终点x坐标是画布宽度,y坐标是画布高度的随机数
context.lineTo(Math.floor(Math.random() * canvas.width), Math.floor(Math.random() * canvas.height));
// 线条的款
context.lineWidth = 0.5;
// 线条的描边属性:颜色透明度
context.strokeStyle = "rgba(50,50,50,0.3)";
// 在画布上画线
context.stroke();
}
// 画随机点函数
function drawDot(canvas, context) {
let px = Math.floor(Math.random() * canvas.width),
py = Math.floor(Math.random() * canvas.height);
context.moveTo(px, py);
context.lineTo(px + 1, py + 1);
context.lineWidth = 0.1;
context.stroke();
}
// 绘制图片,返回 base64 图片
function convertCanvasToImage(canvas) {
try {
return canvas.toDataURL("image/png");
} catch (e) {
console.error("该浏览器版本不支持:canvas.toDataURL(\"image/png\")");
}
}
</script>
</body>
</html>