细心的同学可以发现,现在很多网站当登录多次之后就会出现一个图形验证码,或是当提交表单、或点击获取手机验证码等等场景都会有图形验证码的出现。

那么图形验证码是为了解决什么问题而出现的呢?

什么是图形验证码

图形验证码是验证码的一种。验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的公共全自动程序。可以防止:恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试,实际上用验证码是现在很多网站通行的方式。

既然图形验证码是为了区分机器和人之间的操作,那么我们就可以在图形上绘制一个只有人可以解答的问题。比较常见的是在图片上生成文字验证码,然后用户输入图片上的文字吻合则验证通过。

虽然这种验证方法已经渐渐的被其他更先进的方法所淘汰了(图片上的文字依然可以被程序识别读取),并且前端生成验证码的方式相较于后端安全性不高,但我们的目的只是为了装x,提升程序的安全性只是附带的效果。

登录表单

首先我们需要在在登录表单上额外添加用于输入验证码的FormItem,并且给图形验证码提供一个canvas容器。有时候生成的验证码看不明白,因此需要给验证码添加点击事件用以切换验证码:

<Form ref="loginForm" :model="form" :rules="rules">
<FormItem prop="userName">
<Input v-model="form.userName" placeholder="请输入用户名">
<span slot="prepend">
<Icon :size="16" type="person"></Icon>
</span>
</Input>
</FormItem>
<FormItem prop="password">
<Input type="password" v-model="form.password" placeholder="请输入密码">
<span slot="prepend">
<Icon :size="14" type="locked"></Icon>
</span>
</Input>
</FormItem>
<FormItem prop="valiCode" v-show="this.count">
<Input v-model="form.valiCode" placeholder="请输入验证码">
<span slot="prepend">
<Icon :size="14" type="ios-analytics"></Icon>
</span>
</Input>
<div class="canvas" @click="getImgYanzheng">
<canvas id="canvas"></canvas>
</div>
</FormItem>
<FormItem>
<Button @click="handleSubmit" type="primary" long>登录</Button>
</FormItem>
</Form>

需要用到的属性

表单需要额外添加valiCode用以记录用户输入的验证码。此处我们定义当用户登录失败一次则需要额外输入图形验证码,因此添加count属性,当登陆失败时count++,当然这样的处理方式并不是很严谨,并且用户刷新页面count则会清零。可以在此处可以增加更多限制,如异地登录等,由于本案例完全没有涉及到后端程序,因此只是简单的以count为判断依据。

data() {
return {
form: {
userName: "",// 用户名
password: "",// 密码
valiCode: ""// 验证码
},
count: 0, // 登录次数
show_num: [],// 图形上的文字
}
}

生产图形验证码

页面上为canvas容器绑定的方法getImgYanzheng就是在绘制图形验证码

。在绘制图形验证码时需要为你的验证码定义一个内容集合,此处使用的是:A,B,C,E,F,G,H,J,K,M,N,P,Q,R,S,T,W,X,Y,Z,1,2,3,4,5,6,7,8,9,0,好,医,生。字母中剔除了容易误识别的几个字母并且可以随意加入文字(因此图形验证码也可在做成随机生成四个文字让用户点击,或者生成成语让用户填空等等各种形式)。并且忽略用户大小写,因此需要用到toLowerCase方法。

接下来就是canvas绘图的一些技巧了。

canvas绘图

canvas 元素本身是没有绘图能力的。所有的绘制工作必须在 JavaScript 内部完成:

var c=document.getElementById("myCanvas");
var cxt=c.getContext("2d");

在JavaScript 中使用 id 来寻找 canvas 元素,然后创建context对象,getContext("2d") 对象是内建的 HTML5 对象,拥有多种绘制路径、矩形、圆形、字符以及添加图像的方法。我们可以把canvas 想象成景色而context则是景色呈现的画布。

由于绘制验证码的过程中是从左往右绘制的,因此需要规划好画布的使用范围,另外在验证码绘制时还要加上一些随机的元素使验证码不容易被程序识别。

getImgYanzheng() {
var show_num = [];
var canvas_width = 150; //document.getElementById("canvas").style.width;
var canvas_height = 30; //document.getElementById("canvas").style.height;
var canvas = document.getElementById("canvas"); //获取到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,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; //获取到数组的长度 for (var i = 0; i <= 3; i++) {
var j = Math.floor(Math.random() * aLength); //获取到随机的索引值
var deg = (Math.random() * 30 * Math.PI) / 180; //产生0~30之间的随机弧度
var txt = aCode[j]; //得到随机的一个内容
show_num[i] = txt.toLowerCase();
var x = 10 + i * 20; //文字在canvas上的x坐标
var y = 20 + Math.random() * 8; //文字在canvas上的y坐标
context.font = "bold 23px 微软雅黑"; context.translate(x, y);
context.rotate(deg); context.fillStyle = this.randomColor();
context.fillText(txt, 0, 0); context.rotate(-deg);
context.translate(-x, -y);
}
for (var i = 0; i <= 5; i++) {
//验证码上显示线条
context.strokeStyle = this.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 = this.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();
}
this.show_num = show_num;
},

验证码及线条需要一些随机的颜色:

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 + ")";
}

有了以上两个方法,图形验证码就已经生成完毕了,接下来就是使用的问题了。

使用图形验证码

判断登录次数count,如果登录次数大于0则需要输入验证码:

const self = this;
if (this.count) {
if (this.form.valiCode) {
if (this.show_num.join("") != this.form.valiCode.toLowerCase()) {
self.$Notice.warning({
title: "验证码错误"
});
return;
}
} else {
self.$Notice.warning({
title: "请输入验证码"
});
return;
}
}

当登录失败时需要执行count++并且刷新验证码:

self.count++;
self.getImgYanzheng();
self.$Notice.warning({
title: "登陆失败",
desc: rs.data.msg
});

此时就完成了一个图形验证码的添加工作,同学们快装起来吧。



转评赞就是最大的鼓励

程序员不装x能行?先给登录来一个图形验证码!(canvas实现)的更多相关文章

  1. 程序员初学者参考 ---懂得基础语法后如何做一个自己的case?

    对于很多人来说,我懂java语法,甚至面向对象的特性啦这些都是有了解的,但我就是不会做项目,其实项目真有那么难吗? 对于基础不牢固的人来说,我还不会这个基础点,那个还没学呢,你让我做个项目,我保证做不 ...

  2. 35岁的程序员正在消失?No,我认识了一个50岁的程序员!

    35岁的话题真是无穷无尽.一开始的时候,以为只有社交媒体上会有这种问题的讨论,没想到,公司内部的论坛上也有不少这类的文章.大家各有各的说法,但终究也没有找到银弹似的解决方案. 这段时间,倒是接触了一个 ...

  3. 程序员修仙之路- CXO让我做一个计算器!!

    菜菜呀,个税最近改革了,我得重新计算你的工资呀,我需要个计算器,你开发一个吧 CEO,CTO,CFO于一身的CXO X总,咱不会买一个吗? 菜菜 那不得花钱吗,一块钱也是钱呀··这个计算器支持加减乘除 ...

  4. 写给程序员的机器学习入门 (八) - 卷积神经网络 (CNN) - 图片分类和验证码识别

    这一篇将会介绍卷积神经网络 (CNN),CNN 模型非常适合用来进行图片相关的学习,例如图片分类和验证码识别,也可以配合其他模型实现 OCR. 使用 Python 处理图片 在具体介绍 CNN 之前, ...

  5. 【好程序员笔记分享】——iOS开发之纯代码键盘退出

    -iOS培训,iOS学习-------型技术博客.期待与您交流!------------ iOS开发之纯代码键盘退出(非常简单)     iOS开发之纯代码键盘退出 前面说到了好几次关于键盘退出的,但 ...

  6. The Best Coder and Why? (最牛气的程序员)——精彩!

    原文出处我已经找不到了,总之不是原创了,不过,重新看过,挺受震撼的.程序员出身的我们,或许记不住某些算法细节,但记住他们的名字,也许是应该的. MIT BBS上说微软电话面试的一道题就是“Who do ...

  7. .Net程序员学用Oracle系列(18):PLSQL Developer 攻略

    1.功能说明及使用技巧 1.1.对象浏览器 1.2.SQL 窗口 1.3.测试窗口 1.4.命令窗口 1.5.图表窗口 1.6.报告窗口 1.7.右键菜单 1.8.快速登录技巧 1.9.其它 2.总结 ...

  8. 不要困在自己建造的盒子里——写给.NET程序员(附精彩评论)

    此文章的主旨是希望过于专注.NET程序员在做好工作.写好.NET程序的同时,能分拨出一点时间接触一下.NET之外的东西(例如10%-20%的时间),而不是鼓动大家什么都去学最后什么都学不精,更不是说. ...

  9. 想转行做程序员,是学习JAVA还是Python?哪个更好?

    请大家务必审题,转行做程序员,是程序员,并非数据分析也不是软件测试. 首先声明:这是一篇容易引起撕逼的问答,为了祖国和谐,人民安康,请各位看官尽量理性讨论. 同时,这篇文章是面向一些初入行的朋友进行一 ...

随机推荐

  1. 配置管理-git研究(版本管理)

    1. 安装git2.7 git2.7具体安装步骤如下: [root@host1 ~]# yum install curl-devel expat-devel gettext-devel openssl ...

  2. node 淘宝镜像

    永久使用 打开终端执行 npm config set registry https://registry.npm.taobao.org 临时使用 npm --registry https://regi ...

  3. MarkDown中如何加入上标和下标

    上标 使用<sup></sup>标签包裹的部分就是上标,例如:A<sup>T</sup> 显示效果就是 AT . 下标 使用<sub>< ...

  4. 201800624模拟赛T2——回家路上

    题目描述 很多学生都抱怨浪费在回家路上的时间太长.这天dongdong刚走出学校大门,就听说某段路在施工(但不知道是哪条路),有可能导致他回家的时间会变长. Dongdong给出了一张地图,图中标号为 ...

  5. ppt演讲者视图不可用的解决办法

    1. 关闭ppt 2. 对着桌面右键,选择:nView Desktop Manager 3. 应用程序--增强--去掉“添加Powerpoint幻灯片显示扩展程序(W)”

  6. 排序算法-基数排序(Java)

    package com.rao.sort; import java.util.*; /** * @author Srao * @className RadioSort * @date 2019/12/ ...

  7. 海康威视摄像头+OpenCV+VS2017 图像处理小结(二)

    海康威视摄像头+OpenCV+VS2017 图像处理小结(二) https://blog.csdn.net/o_ha_yo_yepeng/article/details/79825648 目录 一.海 ...

  8. 研究下vc++的abort函数

    最近在调试几个问题时,发现跟abort函数有关,以前只是简单使用,现在却发现不简单,就多留意了下. 简介 abort中止当前进程并返回错误代码.异常终止一个进程.中止当前进程,返回一个错误代码.错误代 ...

  9. Linux下进程间通信方式——pipe(管道)

    每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区,进程B再从内核缓冲区把 ...

  10. 窗体的keyPreview属性

    如果把窗体的keyPreview属性设置为true,那么窗体将比其内的控件优先获得键盘事件的激活权.比如Form1和其内的文本框Text1都准备响应keyPress事件,那么以下代码将首先激活窗体的k ...