【MarsCode IDE】纯前端实现多种随机验证码
尤其是我们经常遇到的管理系统,几乎所有的登录页都会有随机验证码的校验。因此,作为开发者,我们应该持续关注和学习最新的前端技术和安全知识,不断提升自己的能力和水平,以应对日益复杂和多变的安全挑战。背景颜色也是通过随机数的形式进行生成,这里在生成随机背景颜色的时候,也给了一个取值范围,目的是防止生成的背景过深或者过浅,以至于验证码完全看不清。绘制干扰线就是在画布中随机生成几条线段就可以了,设置线段的颜
引言
在当今互联网高度发达的时代,网络安全成为了每一个开发者必须重视的问题。验证码作为一种有效的安全验证手段,被广泛用于防止恶意攻击、自动化脚本以及保护用户账户免受未授权访问。而随机验证码,作为验证码的一种常见形式,通过生成包含随机字符或图像的验证码,极大地提升了用户认证的安全性和可靠性。尤其是我们经常遇到的管理系统,几乎所有的登录页都会有随机验证码的校验。本篇文章就教你如何通过canvas纯前端来实现多种不同形式的验证码。
这次我们不再使用传统的IDE编码工具,介绍一款的全新的智能开发工具MarsCode IDE。
官网地址:https://www.marscode.cn/workbench
MarsCode IDE作为一款云端集成开发环境(IDE),集成了AI编程助手的功能,支持智能补全、智能预测、智能问答等能力。它提供了一个开箱即用的开发环境,开发者无需在本地安装复杂的开发环境,即可通过浏览器访问并编辑项目。MarsCode IDE支持多种主流编程语言和框架,如Python、Go、Java、C++等,并兼容VSCode和JetBrains等主流IDE的代码编辑器,使得开发者可以在一个统一的环境中进行多种语言的开发。
在MarsCode IDE中,开发者可以享受到AI助手带来的诸多便利。例如,通过自然语言注释描述需求,AI助手可以自动生成相应的代码片段,提高编码效率。同时,AI助手还可以实时检测和修复代码中的错误,提供智能优化建议,帮助开发者提高代码质量。此外,MarsCode IDE还内置了丰富的模板和插件市场,开发者可以根据自己的需求选择合适的模板和插件,进一步提升开发效率。
好的,套话完毕,开始正题!!!
创建项目
MarsCode IDE 提供了市面上几乎所有编程语言的模板,使用户能够轻松选用自己熟练语言的模板,即刻开始编程。在此例中,我们将采用热门的前端 JavaScript 框架 Vue.js。借助 MarsCode IDE,用户可以轻松地为项目命名并提供详尽的描述,以确保项目信息准确无误且贴合实际需求。
选择对应的模板就会初始化一个Vue项目工程,直接点击运行就可以跑起来的项目。包括各种依赖以及一些必备文件都是初始化好的。极大的节省了我们自己搭建一个项目的时间。
接下来我们就可以正式开发我们的项目了。
随机数字、字母验证码
首先生成一个随机的包含数字、大小写字母的字符串,字符串可以是任意长度,一般是六到八位就可以了。实现方式是先将所有的字符列出来定义为一个完整的字符串,然后通过随机数的形式从中获取相应的字符。
let identifyCodes: '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIGKLMNOPQRSTUVWXYZ'
let identifyCode = ''
//随机生成一个min-max区间的正整数
function randomNum(min, max) {
return Math.floor(Math.random() * (max - min) + min)
},
//随机生成验证码字符串,取0-identifyCodes长度间的随机一个字符,len就表示生成长度为几的字符串
function makeCode(len) {
for (let i = 0; i < len; i++) {
identifyCode += identifyCodes[this.randomNum(0, identifyCodes.length)]
}
},
其实到这里功能可以说已经实现了,已经生成了一个自定义长度的随机字符串,接下来操作都是优化性的实现。主要是通过canvas来实现的,页面展示的不是一个文本标签,而是一个canvas图像。
- 定义canvas画布
可根据自己的需求,定义不同的宽度
<canvas
id="identify-code"
:width="contentWidth"
:height="contentHeight"
></canvas>
- 绘制背景颜色
背景颜色也是通过随机数的形式进行生成,这里在生成随机背景颜色的时候,也给了一个取值范围,目的是防止生成的背景过深或者过浅,以至于验证码完全看不清。本人之前取值范围为190-240,效果感觉还不错。
let canvas = document.getElementById("identify-code");
let ctx = canvas.getContext("2d");
function randomColor(min, max) {
let r = this.randomNum(min, max);
let g = this.randomNum(min, max);
let b = this.randomNum(min, max);
return "rgb(" + r + "," + g + "," + b + ")";
},
- 绘制文字
同样的字体颜色也是通过随机数的形式生成,字体大小也是随机生成,也要给定区间防止过大过小;除此之外还可以修改一下文字的坐标和旋转角度
ctx.fillStyle = this.randomColor(min, max);
ctx.font = this.randomNum(min, max) + "px SimHei";
let deg = this.randomNum(-30, 30);
// 修改坐标原点和旋转角度
ctx.translate(x, y);
ctx.rotate((deg * Math.PI) / 270);
//绘制字符
ctx.fillText(txt, 0, 0);
// 恢复坐标原点和旋转角度
ctx.rotate((-deg * Math.PI) / 270);
ctx.translate(-x, -y);
- 绘制干扰线
绘制干扰线就是在画布中随机生成几条线段就可以了,设置线段的颜色为随机值,画线段就是确认两个位置坐标,也都是通过随机数的方式生成,但要确保坐标位置不能超出画布的宽高。
ctx.strokeStyle = this.randomColor(
this.lineColorMin,
this.lineColorMax
);
ctx.beginPath();
ctx.moveTo(
this.randomNum(0, this.contentWidth),
this.randomNum(0, this.contentHeight)
);
ctx.lineTo(
this.randomNum(0, this.contentWidth),
this.randomNum(0, this.contentHeight)
);
ctx.stroke();
- 绘制干扰点
生成的是颜色随机,圆心随机但半径为1的小圆点,生成的个数可自定义,循环多少次就生成多少个。
ctx.fillStyle = this.randomColor(0, 255);
ctx.beginPath();
ctx.arc(
this.randomNum(0, this.contentWidth),
this.randomNum(0, this.contentHeight),
1,
0,
2 * Math.PI
);
ctx.fill();
最终效果实现的效果就是这样式的,如果想刷新验证码,只需要给canvas绑个点击事件,重新调一下上面生成验证码的方法就可以了。
做验证码嘛,最终肯定是要检验用户填写的验证码是否正确。我们只需要判断一下用户填写的验证码与我们一开始生成的identifyCode
是否一致就可以了。
加减乘除法验证码
除了上面提到的随机字符验证码之外,加减乘除法验证码也是很常见的。这种加减乘除法一般都是非常简单的运算,不会过于复杂。一般不会有人用微分方程来作为验证码,哈哈哈
运算类的验证码,只需要生成两个简单的数字以及 + - * / 四种运算符号就可以了。数字生成1-10之间的,运算符只需要从operators
中随机抽取一位就可以了。
var num1 = Math.floor(Math.random() * 10) + 1; // Random number between 1 and 10
var num2 = Math.floor(Math.random() * 10) + 1; // Random number between 1 and 10
var operators = ['+', '-', '*', '/'];
var operator = operators[Math.floor(Math.random() * operators.length)];
当operator是/的时候,就需要对数字做一些特殊处理,保证最终可以正常的进行运算。
所以需要确保除数不为零且被除数能被除数整除。
if (operator === '/') {
while (num1 % num2 !== 0 || num2 === 0) {
num1 = Math.floor(Math.random() * 10) + 1;
num2 = Math.floor(Math.random() * 10) + 1;
}
}
为了避免出现负数的情况也可以做一些处理。
//目的是防止运算结果为负数
if (operator === "-" && num1 < num2) {
[num1, num2] = [num2, num1];
}
数字和运算符随机生成好之后就可以开始绘制了。为了实现数字和字符偏移旋转一点角度,并没有将两个数字和运算符拼接成一个字符串绘制,而是分开绘制的。
let arr = [num1, operator, num2];
for (let i = 0; i < 3; i++) {
ctx.font = `bold ${i == 1 ? 40 : 30}px Arial`;
ctx.fillStyle = randomColor(80, 150);
ctx.textAlign = "center";
ctx.textBaseline = "middle";
ctx.shadowColor = "rgba(0, 0, 0, 0.3)";
ctx.shadowOffsetX = 2;
ctx.shadowOffsetY = 2;
ctx.shadowBlur = 4;
let str: string|number = arr[i];
ctx.fillText(String(str), (positionX += 20), i == 1 && str == "*" ? 20 : 15);
ctx.shadowColor = "transparent";
}
我们也可以绘制一些小的干扰点。
const randomCircle = () => {
const numCircles = 30;
for (let i = 0; i < numCircles; i++) {
const x = randomNum(0, 100);
const y = randomNum(0, 30);
const radius = randomNum(1, 2);
ctx.fillStyle = randomColor(80, 150);
ctx.beginPath();
ctx.arc(x, y, radius, 0, 2 * Math.PI);
ctx.fill();
}
};
最终的校验是检查用户计算结果是否正确,所以系统需要先计算出正确的结果,然后与用户输入结果进行比较,一致的话即为校验通过。
//计算结果
function calc() {
switch (operator) {
case "+":
return num1 + num2;
case "-":
return num1 - num2;
case "*":
return num1 * num2;
case "/":
return num1 / num2;
default:
return NaN;
}
}
滑动验证码
经常遇到的还有另外一种验证的形式就是滑动验证码。具体的实现思路就是为div设定一个初始背景颜色(即未激活状态的颜色),并在此颜色上叠加一个绿色区域(与初始背景对齐)。通过监测鼠标的水平偏移量(left值),动态调整绿色区域的宽度。若鼠标在未达到最大偏移量时释放,绿色区域将回归初始宽度;而一旦达到最大偏移量,则视为校验通过,此时将更新校验提示信息和图形。
-
第一步就是先绘制页面上的元素。一共分为三部分。最外层的div,需要拖动的元素以及拖动滑块之后要展示的绿色区域。
-
初始化滑块,主要是初始化滑块的位置,以及为滑块绑定鼠标按下的监听事件。
// 初始化
initDrag() {
//在滑动验证容器文本写入“拖动滑块验证”
this.dragText.textContent = “拖动滑块验证”;
//给滑块添加鼠标按下监听
this.dragHandler.addEventListener(“mousedown”, this.onDragHandlerMouseDown);//初始化滑块移动量 this.dragHandler.style.left = 0; //初始化绿色背景 this.dragBg.style.width = 0; this.dragText.style.color = ""; this.dragHandler.setAttribute("class", "dragHandlerBg");
},
-
滑块验证码是一个从鼠标按下->鼠标移动->鼠标松开的过程,当鼠标按下之后,我们还要监听鼠标移动和鼠标松开的事件。
// 鼠标按下
onDragHandlerMouseDown() {
//鼠标移动监听
document.addEventListener(“mousemove”, this.onDragHandlerMouseMove);
//鼠标松开监听
document.addEventListener(“mouseup”, this.onDragHandlerMouseUp);
}, -
鼠标移动的时候我们要改变小的div块的位置,以及滑过位置的背景颜色。
var left = event.clientX - this.dragHandler.clientWidth / 2 - dragX.left;
:这行代码计算滑块的新位置。event.clientX 是鼠标指针相对于视口的水平位置。this.dragHandler.clientWidth / 2 是滑块宽度的一半,用于确保滑块中心对准鼠标指针(这通常是为了提供更好的用户体验)。dragX.left 是滑块背景元素左边缘相对于视口的水平位置。通过这三个值的计算,可以得到滑块相对于其背景元素左边缘的水平偏移量。滑块最小位置的位置为0,最大位置为this.maxHandlerOffset = dragContainer.clientWidth - dragHandler.clientWidth;
当滑块的位置到达最大位置处便证明验证成功。onDragHandlerMouseMove() {
//滑块移动量
let dragX = this.dragBg?.getBoundingClientRect()||{}
var left = event.clientX - this.dragHandler.clientWidth / 2 - dragX.left;if(left < 0) { // 滑动小于0设为0 left = 0; } else if(left >= this.maxHandlerOffset) { // 滑动超过最大偏移量则校验成功 left = this.maxHandlerOffset; this.verifySucc(); } // 超过最大偏移量,不增加绿色区域宽度 if(left>this.maxHandlerOffset) return; // 滑块移动量(距离左侧的定位) this.dragHandler.style.left = left + "px"; // 绿色背景的长度 this.dragBg.style.width = left + "px";
},
-
验证成功之后,我们将文字修改为验证通过,改变滑块的图标并移除绑定的事件。
// 滑动完成
verifySucc() {
//容器文本的文字改为白色“验证通过”字体
this.dragText.textContent = “验证通过”;
this.dragText.style.color = “white”;
//验证通过的滑块背景
this.dragHandler.setAttribute(“class”, “dragHandlerOkBg”);
//移除鼠标按下监听
this.dragHandler.removeEventListener(“mousedown”, this.onDragHandlerMouseDown);
//移除 鼠标移动监听
document.removeEventListener(“mousemove”, this.onDragHandlerMouseMove);
//移除鼠标松开监听
document.removeEventListener(“mouseup”, this.onDragHandlerMouseUp);
}, -
没验证通过的情况下,会触发鼠标松开事件。会将滑块的位置恢复到原始位置,并初始化绿色背景。
// 鼠标抬起
onDragHandlerMouseUp() {
//移除鼠标移动监听
document.removeEventListener(“mousemove”, this.onDragHandlerMouseMove);
//移除鼠标松开监听
document.removeEventListener(“mouseup”, this.onDragHandlerMouseUp);
//初始化滑块移动量
this.dragHandler.style.left = 0;
//初始化绿色背景
this.dragBg.style.width = 0;
},
最终实现的效果:
随着前端技术的不断发展和创新,我们有理由相信,未来的验证码将更加智能化、个性化,并能够更好地融入用户的使用场景和流程中。因此,作为开发者,我们应该持续关注和学习最新的前端技术和安全知识,不断提升自己的能力和水平,以应对日益复杂和多变的安全挑战。
在整个开发过程中,亲身体验到MarsCode IDE是一款功能强大、高效便捷的云端集成开发环境。它融合了项目开发和编程学习的广泛性需求,为开发者带来了全新的智能编程体验。无论是个人项目开发、团队协作开发还是编程学习和教育,MarsCode IDE都能提供有力的支持。在未来,随着技术的不断发展和创新,相信MarsCode IDE将会为开发者带来更多惊喜和便利。
更多推荐
所有评论(0)