引言

在当今互联网高度发达的时代,网络安全成为了每一个开发者必须重视的问题。验证码作为一种有效的安全验证手段,被广泛用于防止恶意攻击、自动化脚本以及保护用户账户免受未授权访问。而随机验证码,作为验证码的一种常见形式,通过生成包含随机字符或图像的验证码,极大地提升了用户认证的安全性和可靠性。尤其是我们经常遇到的管理系统,几乎所有的登录页都会有随机验证码的校验。本篇文章就教你如何通过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图像。

  1. 定义canvas画布

可根据自己的需求,定义不同的宽度

<canvas
  id="identify-code"
  :width="contentWidth"
  :height="contentHeight"
></canvas>
  1. 绘制背景颜色

背景颜色也是通过随机数的形式进行生成,这里在生成随机背景颜色的时候,也给了一个取值范围,目的是防止生成的背景过深或者过浅,以至于验证码完全看不清。本人之前取值范围为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 + ")";
},
  1. 绘制文字

同样的字体颜色也是通过随机数的形式生成,字体大小也是随机生成,也要给定区间防止过大过小;除此之外还可以修改一下文字的坐标和旋转角度

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);
  1. 绘制干扰线

绘制干扰线就是在画布中随机生成几条线段就可以了,设置线段的颜色为随机值,画线段就是确认两个位置坐标,也都是通过随机数的方式生成,但要确保坐标位置不能超出画布的宽高。

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. 绘制干扰点

生成的是颜色随机,圆心随机但半径为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值),动态调整绿色区域的宽度。若鼠标在未达到最大偏移量时释放,绿色区域将回归初始宽度;而一旦达到最大偏移量,则视为校验通过,此时将更新校验提示信息和图形。

  1. 第一步就是先绘制页面上的元素。一共分为三部分。最外层的div,需要拖动的元素以及拖动滑块之后要展示的绿色区域。

  2. 初始化滑块,主要是初始化滑块的位置,以及为滑块绑定鼠标按下的监听事件。

    // 初始化
    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");
    

    },

  3. 滑块验证码是一个从鼠标按下->鼠标移动->鼠标松开的过程,当鼠标按下之后,我们还要监听鼠标移动和鼠标松开的事件。

    // 鼠标按下
    onDragHandlerMouseDown() {
    //鼠标移动监听
    document.addEventListener(“mousemove”, this.onDragHandlerMouseMove);
    //鼠标松开监听
    document.addEventListener(“mouseup”, this.onDragHandlerMouseUp);
    },

  4. 鼠标移动的时候我们要改变小的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";
    

    },

  5. 验证成功之后,我们将文字修改为验证通过,改变滑块的图标并移除绑定的事件。

    // 滑动完成
    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);
    },

  6. 没验证通过的情况下,会触发鼠标松开事件。会将滑块的位置恢复到原始位置,并初始化绿色背景。

    // 鼠标抬起
    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将会为开发者带来更多惊喜和便利。

Logo

汇聚全球AI编程工具,助力开发者即刻编程。

更多推荐