最容易使用的验证码控件(附代码)

合集下载

八爪鱼验证码登陆-控件识别方法(7.0版本)

八爪鱼验证码登陆-控件识别方法(7.0版本)

八爪鱼验证码登陆-控件识别方法(7.0版本)本文给大家演示登陆界面有验证码或者其他验证(如滑块验证)的网站通过八爪鱼控件识别进行数据采集的方式。

所讲示例采集数据网址为/login.aspx小贴士:通过八爪鱼的控件进行识别,这种方式如果需要自动识别,就需要购买验证码套餐,如果不购买也只能进行单机采集然后手动输入,注意这种方法只能是输入验证码的框才可以用这种方式。

步骤1 登陆八爪鱼7.0采集器→点击新建任务→自定义采集,进入到任务配置页面:然后输入网址→保存网址,系统会进入到流程设计页面并自动打开前面输入的网址。

验证码登陆-控件识别方法-图1:输入网址接下来步骤是输入用户名密码了,八爪鱼模拟的是人的操作行为,所以这一步过程也很简单步骤2 在浏览器中鼠标点击用户名输入框→在右边弹出的提示里面选择“输入文字”→输入自己的用户名→选择“确定”。

同样的方式输入密码,这样输入用户名密码的步骤就完成了。

验证码登陆-控件识别方法-图2:输入密码验证码登陆-控件识别方法-图3:输入密码这里八爪鱼采集器需要知道1.验证码图片在哪里2.输入框验证码的框在哪里步骤3 点击下方浏览器中验证码图片的位置→按照提示框中的提示选择浏览器中的验证码框→再按照提示框中的提示点击浏览器中的登陆按钮验证码登陆-控件识别方法-图4:点击验证码输入框验证码登陆-控件识别方法-图5:点击验证码图片位置、登录按钮接下来需要配置验证码输入失败和成功的两种场景步骤4 点击提示框中的确认按钮,系统会自动提交一个错误的验证码→然后点击浏览器中的“验证码不正确”提示→再点击提示框中的确认按钮→选择提示框中的“开始配置识别成功场景”→在提示框中输入显示出来的验证码→选择提示框中的“应用到网页并完成配置”选项 验证码登陆-控件识别方法-图6:点击确认按钮验证码登陆-控件识别方法-图7:配置验证码输入失败场景验证码登陆-控件识别方法-图8:配置验证码输入成功场景验证码登陆-控件识别方法-图9:配置验证码输入成功场景上述操作中验证码识别就完成了,接下来需要手动执行这个流程,任务会自动进去到登陆界面步骤5 点击“流程”按钮→进入到流程界面→手动点击流程步骤(可以看到浏览器中会按照会执行这些步骤)→点到识别验证码步骤时→在辅助模式选项中输入浏览器中当前显示的验证码→选择应用到网页并提交验证码登陆-控件识别方法-图10:辅助模式选项这样操作之后,可以看到任务就正常登陆进去了。

kaptcha谷歌验证码工具

kaptcha谷歌验证码工具

kaptcha⾕歌验证码⼯具Kaptcha 简介Kaptcha 是⼀个可⾼度配置的实⽤验证码⽣成⼯具,可⾃由配置的选项如:验证码的字体验证码字体的⼤⼩验证码字体的字体颜⾊验证码内容的范围(数字,字母,中⽂汉字!)验证码图⽚的⼤⼩,边框,边框粗细,边框颜⾊验证码的⼲扰线验证码的样式(鱼眼样式、3D、普通模糊、...)Kaptcha 详细配置表kaptcha.border图⽚边框,合法值:yes , no yeskaptcha.border.color边框颜⾊,合法值: r,g,b (and optional alpha)或者 white,black,blue.blackkaptcha.image.width图⽚宽200kaptcha.image.height图⽚⾼50kaptcha.producer.impl图⽚实现类com.google.code.kaptcha.impl.DefaultKaptcha kaptcha.textproducer.impl⽂本实现类com.google.code.kaptcha.text.impl.DefaultTextCreator kaptcha.textproducer.char.string⽂本集合,验证码值从此集合中获取abcde2345678gfynmnpwxkaptcha.textproducer.char.length验证码长度5s字体Arial, Courierkaptcha.textproducer.font.size字体⼤⼩40px.kaptcha.textproducer.font.color字体颜⾊,合法值: r,g,b 或者white,black,blue.blackkaptcha.textproducer.char.space⽂字间隔2kaptcha.noise.impl⼲扰实现类com.google.code.kaptcha.impl.DefaultNoisekaptcha.noise.color⼲扰颜⾊,合法值: r,g,b 或者white,black,blue.blackkaptcha.obscurificator.impl 图⽚样式:<br />⽔纹com.google.code.kaptcha.impl.WaterRipple<br />鱼眼com.google.code.kaptcha.impl.FishEyeGimpy<br />阴影com.google.code.kaptcha.impl.ShadowGimpycom.google.code.kaptcha.impl.WaterRipplekaptcha.background.impl背景实现类com.google.code.kaptcha.impl.DefaultBackground kaptcha.background.clear.from背景颜⾊渐变,开始颜⾊light greykaptcha.background.clear.to背景颜⾊渐变,结束颜⾊whitekaptcha.word.impl⽂字渲染器com.google.code.kaptcha.text.impl.DefaultWordRenderer kaptcha.session.key session key KAPTCHA_SESSION_KEYkaptcha.session.date session date KAPTCHA_SESSION_DATE⽤法<dependency><groupId>com.google.code.kaptcha</groupId><artifactId>kaptcha</artifactId><version>2.3</version></dependency>或者<dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version></dependency>主要代码KaptchaConfig.java@Componentpublic class KaptchaConfig {@Beanpublic DefaultKaptcha getDDefaultKaptcha() {DefaultKaptcha dk = new DefaultKaptcha();Properties properties = new Properties();// 图⽚边框properties.setProperty("kaptcha.border", "yes");// 边框颜⾊properties.setProperty("kaptcha.border.color", "105,179,90");// 字体颜⾊properties.setProperty("kaptcha.textproducer.font.color", "red");// 图⽚宽properties.setProperty("kaptcha.image.width", "110");// 图⽚⾼properties.setProperty("kaptcha.image.height", "40");// 字体⼤⼩properties.setProperty("kaptcha.textproducer.font.size", "30");// session keyproperties.setProperty("kaptcha.session.key", "code");// 验证码长度properties.setProperty("kaptcha.textproducer.char.length", "4");// 字体properties.setProperty("s", "宋体,楷体,微软雅⿊");Config config = new Config(properties);dk.setConfig(config);return dk;}}KaptchaController.java@Controllerpublic class KaptchaController {/*** 验证码⼯具*/@AutowiredDefaultKaptcha defaultKaptcha;@RequestMapping("/defaultKaptcha")public void defaultKaptcha(HttpServletRequest request, HttpServletResponse response) throws Exception { byte[] captcha = null;ByteArrayOutputStream out = new ByteArrayOutputStream();try {// 将⽣成的验证码保存在session中String createText = defaultKaptcha.createText();request.getSession().setAttribute("rightCode", createText);BufferedImage bi = defaultKaptcha.createImage(createText);ImageIO.write(bi, "jpg", out);} catch (Exception e) {response.sendError(HttpServletResponse.SC_NOT_FOUND);return;}captcha = out.toByteArray();response.setHeader("Cache-Control", "no-store");response.setHeader("Pragma", "no-cache");response.setDateHeader("Expires", 0);response.setContentType("image/jpeg");ServletOutputStream sout = response.getOutputStream();sout.write(captcha);sout.flush();sout.close();}/*** 校对验证码** @param request* @param response*/@RequestMapping(value = "/login", method = RequestMethod.POST)public ModelAndView imgvrifyControllerDefaultKaptcha(HttpServletRequest request, HttpServletResponse response) {ModelAndView model = new ModelAndView();String rightCode = (String) request.getSession().getAttribute("rightCode");String tryCode = request.getParameter("tryCode");System.out.println("rightCode:" + rightCode + " ———— tryCode:" + tryCode);if (!rightCode.equals(tryCode)) {model.addObject("info", "验证码错误,请再输⼀次!");model.setViewName("login");} else {model.addObject("info", "登陆成功");model.setViewName("index");}return model;}/*** 返回⾸页** @return*/@RequestMapping(value = "/login", method = RequestMethod.GET)public ModelAndView index() {return new ModelAndView("login");}}前端页⾯login.html<!DOCTYPE html><html xmlns:th=""><head lang="en"><meta charset="UTF-8"><title>Insert title here</title><link rel="stylesheet" href="https:///twitter-bootstrap/3.3.7/css/bootstrap.min.css"><script src="https:///jquery/2.1.1/jquery.min.js"></script><script src="https:///twitter-bootstrap/3.3.7/js/bootstrap.min.js"></script><style type="text/css">body {padding: 10px;}#inputtext {width: 100%;}#login{width: 300px;margin:0px auto;padding-top: 60px;}#flushimg{text-decoration: underline;}#butt{width: 60%;}</style></head><body><div id="login"><form action="/login" method="post"><h2 align="center">L O G I N</h2><br/><br/><input type="text" name="userName" class="form-control" id="inputtext" required autofocus placeholder="-----请输⼊⽤户名-----"/><br/> <input type="password" name="userName" class="form-control" id="inputtext" required placeholder="----请输⼊⽤户密码----"/><br/> <div id="flushimg"><img alt="验证码" onclick="this.src='/defaultKaptcha?d=' + new Date()*1" src="/defaultKaptcha"/><a>看不清?点击图⽚刷新⼀下</a></div><input type="text" name="tryCode" class="form-control" required placeholder="-----请输⼊验证码-----"/><h4 th:text="${info}" style="color: red"></h4><input type="checkbox" name="rememberMe"/>记住我<br/><div style="width: 100%;text-align: center;"><input type="submit" value="登录" id="butt" class="btn btn-success"/></div></form></div></body></html>index.html<!DOCTYPE html><html><head><meta charset="UTF-8"><title>Insert title here</title></head><body><h2>验证成功!</h2></body></html>页⾯效果地址栏输⼊:localhost:8080/login。

vue实现登录时图形验证码

vue实现登录时图形验证码

vue实现登录时图形验证码本⽂实例为⼤家分享了vue实现登录时图形验证码的具体代码,供⼤家参考,具体内容如下效果图:点击图案可以切换字符1.新建 Identify.vue 组件<template><div><canvasid="s-canvas":width="contentWidth":height="contentHeight"></canvas></div></template><script>export default {name: "identify",props: {identifyCode: {type: String,default: ''},fontSizeMin: {type: Number,default: 28},fontSizeMax: {type: Number,default: 40},backgroundColorMin: {type: Number,default: 180},backgroundColorMax: {type: Number,default: 240},colorMin: {type: Number,default: 50},colorMax: {type: Number,default: 160},lineColorMin: {type: Number,default: 40},lineColorMax: {type: Number,default: 180},dotColorMin: {type: Number,default: 0},dotColorMax: {type: Number,default: 255},contentWidth: {type: Number,default: 130},contentHeight: {type: Number,default: 40}},methods:{// ⽣成⼀个随机数randomNum (min, max) {return Math.floor(Math.random() * (max - min) + min)},// ⽣成⼀个随机的颜⾊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 + ')'},drawPic () {let canvas = document.getElementById('s-canvas')let ctx = canvas.getContext('2d')ctx.textBaseline = 'bottom'// 绘制背景ctx.fillStyle = this.randomColor(this.backgroundColorMin,this.backgroundColorMax)ctx.fillRect(0, 0, this.contentWidth, this.contentHeight)// 绘制⽂字for (let i = 0; i < this.identifyCode.length; i++) {this.drawText(ctx, this.identifyCode[i], i)}this.drawLine(ctx)this.drawDot(ctx)},drawText (ctx, txt, i) {ctx.fillStyle = this.randomColor(this.colorMin, this.colorMax)ctx.font =this.randomNum(this.fontSizeMin, this.fontSizeMax) + 'px SimHei' let x = (i + 1) * (this.contentWidth / (this.identifyCode.length + 1))let y = this.randomNum(this.fontSizeMax, this.contentHeight - 5)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)},drawLine (ctx) {// 绘制⼲扰线for (let i = 0; i < 2; i++) {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()}},drawDot (ctx) {// 绘制⼲扰点for (let i = 0; i < 20; i++) {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()}}},watch: {identifyCode () {this.drawPic()}},mounted () {this.drawPic()}}</script><style lang="scss" scoped>#s-canvas {height: 38px;}</style>2.在⽗组件 index.vue注册使⽤<template><div @click="refreshCode" style="cursor: pointer;"><Identify :identifyCode="identifyCode" ></Identify></div></template><script>import Identify from '@/components/test/identify'export default {name: "index",components:{Identify},data(){return {identifyCode: '',// 验证码规则identifyCodes: '123456789ABCDEFGHGKMNPQRSTUVWXYZ',}},methods:{// 切换验证码refreshCode() {this.identifyCode = ''this.makeCode(this.identifyCodes, 4)console.log(this.identifyCode)},// ⽣成随机验证码makeCode(o, l) {for (let i = 0; i<l; i++) {this.identifyCode += this.identifyCodes[Math.floor(Math.random() * (this.identifyCodes.length - 0) + 0)]}},mounted() {this.refreshCode()}}</script><style scoped></style>以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

6位验证码 正则

6位验证码 正则

6位验证码正则
以下是一个用 Python 语言实现的匹配 6 位验证码的正则表达式:
```python
import re
def verification_code_validator(code):
pattern = r'^\d{6}$'
if re.match(pattern, code):
return True
else:
return False
```
在这个函数中,我们定义了一个正则表达式模式 `r'^\d{6}$'`。

它表示一个以数字开头并结尾,长度为 6 的字符串。

具体解释如下:
- `^` 表示匹配字符串的开头。

- `\d` 表示匹配数字字符。

- `{6}` 表示前面的字符(即数字)出现 6 次。

- `$` 表示匹配字符串的结尾。

使用 `re.match()` 方法来检查输入的验证码是否符合正则表达式模式。

如果匹配成功,函数返回 `True`,表示验证码有效;否则,返回 `False`,表示验证码无效。

你可以根据实际需求对这个正则表达式进行修改,例如如果验证码可以包含字母,可以将 `\d` 改为 `[a-zA-Z0-9]`。

希望这可以帮助到你!如果还有其他问题,请随时提问。

验证码大全

验证码大全

验证码以下是目前主流验证码,如无特殊要求,请务必使用小写录入,切记不要使用大写!xyxkkejwh gkghhzdx以上验证码来自(全球最大交友网),7-10个字母,输入时间限制很很短(20秒左右),需要快速录入,否则无效!rs4jr9g9 f5hqwp8r q53tgqcv以上验证码来自,网站设定的输入时间限制较长,需要慢慢的准确输入。

lifolid上图尤其要引起注意,这种类型的验证码是纯字母的,看到像数字7的一定是字母L,所以不要输错,毕竟打错是影响准确率的!Cebus possession Hotchkiss 60-48s. $523.514 Linehan此类验证码来自,需要区分大小写!即看到大写就录入大写,看到小写就小写录入!输入时两段码之间打一个空格。

比较繁琐的验证码,有空格,有"-",还有小数点"."和“$”等等符号。

3tx2x6u5 t3gtn8cs g6t5xhnahotmail的验证码系列,主流码出码在TT LA BO里,固定的8个字符(字母加数字混合),输入时间限制很长,可以慢慢输入。

bbyume4h ny8bp4(雅虎)的验证码系列(字母加数字混合),输入时间限制很较短,需要快速录入,所以容易吃码。

FCYVEA 4DZTDT EEV3EW此种验证码比较少见,来自荷兰egv网,具体是否必须区分大小写,不得而知,可以首选大写录入!rabresub miadocaill flystra frfajiv这种类型的验证码是(谷歌)和其旗下(优兔贝视频站)的,红绿蓝三种颜色,东倒西歪,熟练了蛮好打的,小写输入。

grocery johntra forms这也是超级繁琐的验证码,一般情况下上不多见,不必理会。

fihWnTO注意:这类型的验证码需要区分大小写,PF类型验证码,即看到大写字母就输入大写字母,看到小写就小写,必须严格按照图片显示的字母输入!pleasuring brighteners backwooding据我所知这种验证码是AOL中国邮件服务网站的,设计的非常不错的验证码类型,一般很难设计出自动识别的软件来攻克此种验证码。

php手机短信验证代码(共9篇)

php手机短信验证代码(共9篇)

php手机短信验证代码(共9篇)篇一:短信验证码PHP代码篇二:用维泰SDK实现发送短信验证码php源码phprequire &quot;httprequest.php&quot;;/*&#39; 该示范程序通过:88/ 发送短信&#39;&#39;返回值:&#39;返回值大于0表示成功,小于0表示失败。

如果失败,返回信息还包括失败原因的文字描述。

&#39;说明:&#39;返回成功仅表示服务器已经成功接收客户提交的任务,并不表示对方已经收到短信。

&#39;因移动公司对短信内容审核严格,如测试未收到,请及时联系客服&#39;请不要发送&quot;测试&quot;,&quot;你好&quot;,&quot;abc&quot;等无意义的内容*/function smsend($strMobile,$strText){//发送短信的服务器地址$strServerURL = &quot;:88/cgi/sendsmsbatch.asp&quot;;// 短信账号:免费申请,如有问题请联系QQ732055019// :88/mis/user_reg_form.asp?interest=sms.api $strUser= &quot;username&quot;;// 验证密码: 初始密码由平台通过短信发送, 用户可登录平台自己修改$strPass= &quot;userpass&quot;;if($strUser==&quot;&quot;){echo (&quot;短信帐号没有设定!&quot;);return;}if($strPass==&quot;&quot;){echo (&quot;短信验证密码没有设定!&quot;);return;}if($strMobile==&quot;&quot;){echo (&quot;短信接收号码无效!&quot;);return;}if($strText==&quot;undefined|| $strText==&quot;&quot;){echo (&quot;短信内容不能为空!&quot;);return;}if(strlen($strText)69){echo (&quot;短信内容不能超过69个字&quot;);return;}//准备表单:使用urlencode对参数进行编码,字符集gb2312 $strForm = &quot;User=. urlencode($strUser);$strForm .= &quot;&amp;Pass=. urlencode($strPass);$strForm .= &quot;&amp;Mobile=. urlencode($strMobile);$strForm .= &quot;&amp;Text=. urlencode($strText);$h= new HttpRequest();$s= $h-request(&quot;GET&quot;,$strServerURL.&quot;?&quot;.$strFor m,&quot;&quot;);if (strpos($s,&quot;SUCCESS&quot;)===false){//出现错误echo (&quot;短信通知发送失败!br.$s);}else {//发送成功echo(&quot;短信通知发送成功!&quot;);}}htmlheadtitle发送短信通知/titlemeta http-equiv=&quot;Content-Typecontent=&quot;text/html; charset=gb2312&quot;/headbodybrdiv class=&quot;title1&quot;发送短信通知/divdiv class=&quot;content1&quot;$strMobile=&quot;132****9999&quot;;//接收短信的手机号码 $strText=&quot;Test SMS&quot;;//短信内容(不要超过69个字) smsend($strMobile,$strText);/div/body/htmlphp //httprequest.phpclass HttpRequest{var $_host;var $_uri;var $_port;var $_response;function parseURL($url){$req = $url;$pos = strpos($req, &#39;://&#39;);$this-_protocol = strtolower(substr($req, 0, $pos));$req = substr($req, $pos+3);$pos = strpos($req, &#39;/&#39;);if($pos === false)$pos = strlen($req);$host = substr($req, 0, $pos);if(strpos($host, &#39;:&#39;) === false){$this-_host = $host;$this-_port = ($this-_protocol == &#39;https&#39;) ? 443 : 80;}else{list($this-_host, $this-_port) = explode(&#39;:&#39;, $host);}$this-_uri = substr($req, $pos);if($this-_uri == &#39;&#39;)$this-_uri = &#39;/&#39;;}function request($method , $url, $sPostData){$this-parseURL($url);$fp = pfsockopen( $this-_host, $this-_port, &amp;$errno, &amp;$errstr, 120); if( !$fp ) {echo &quot;$errstr ($errno)br\n&quot;;return &quot;&quot;;}if( strtoupper($method) == &quot;GET&quot;){fputs( $fp, &quot;GET &quot;.$this-_uri.HTTP/1.0\r\n&quot;); }else if( strtoupper($method) == &quot;POST) {fputs( $fp, &quot;POST &quot;.$this-_uri.HTTP/1.0\r\n&quot;); }fputs( $fp, &quot;Accept: */*\n&quot;);fputs( $fp, &quot;Host: &quot;.$this-_host.&quot;\r\n&quot;);fputs( $fp, &quot;Connection: Close\r\n&quot;);if( strtoupper($method) == &quot;POST) {$strlength = strlen( $data);fputs( $fp, &quot;Content-type:application/x-www-form-urlencoded\r\n); fputs( $fp, &quot;Content-length: &quot;.$strlength.&quot;\r\n&quot;);fputs($fp, &quot;\r\n&quot;);fputs( $fp, $data.&quot;\r\n&quot;);}else{fputs($fp, &quot;\r\n&quot;);}$this-_response = &quot;&quot;;while( !feof( $fp ) ) {$this-_response .= fgets( $fp, 4096);}fclose( $fp);$s = $this-getResponseBody();return $s;}function getResponse(){return $this-_response;}function getResponseBody(){$sKey = &quot;\r\n\r\n&quot;;$pos = strpos($this-_response,$sKey);if($pos===false) return &quot;&quot;;$str= substr($this-_response,$pos + 4);return $str;}}篇三:用免费短信验证码SDK实现手机注册验证功能用免费短信验证码SDK实现手机注册验证功能第一步获取短信SDK请到Mob官网下载最新版本的SDK,下载回来后解压,可以看到下面的文件结构:其中SMS_SDK.framework 为依赖库文件SMS_SDKDemo 为示例demo ,其中保存了短信SDK的演示项目代码。

easy-captcha 验证码 案例

easy-captcha 验证码 案例

【主题】easy-captcha验证码案例分析【内容】1. 背景介绍easy-captcha是一个基于Java的开源验证码生成工具,可以轻松地生成各种类型的验证码,包括数字、字母、算术运算等,适用于Web 应用、移动应用等各种场景。

2. easy-captcha的特点easy-captcha具有以下特点:- 简单易用:通过简单的配置即可生成各种类型的验证码。

- 自定义性强:支持自定义验证码长度、宽度、高度等参数。

- 多样化:支持数字、字母、算术运算等多种类型的验证码。

- 高安全性:生成的验证码具有一定的防伪能力,能有效防止恶意攻击和爬虫。

3. easy-captcha在实际项目中的应用以某电商全球信息站为例,介绍easy-captcha在实际项目中的应用情况:- 用户注册:在用户注册页面使用easy-captcha生成验证码,确保用户输入信息的准确性。

- 找回密码:在用户找回密码时使用easy-captcha生成验证码,确保用户身份的真实性。

- 登入验证:在用户登入时使用easy-captcha生成验证码,防止暴力破解和恶意登入。

4. easy-captcha的使用方法介绍easy-captcha的使用方法,包括依赖引入、配置参数、验证码生成等步骤。

5. easy-captcha的优化与性能提升针对easy-captcha在实际应用中可能遇到的性能问题,介绍优化方法,包括验证码缓存、验证码预生成等技术手段,提升验证码生成的性能和用户体验。

6. 结语总结easy-captcha在验证码生成方面的优势和应用案例,展望其在未来的发展前景。

同时提醒开发者在使用easy-captcha时需要注意安全性和性能方面的问题,合理使用并进行定期维护。

7. easy-captcha在安全性方面的应用easy-captcha不仅可以用来增强用户体验,同时也在保障系统安全性方面扮演着重要的角色。

在实际使用中,easy-captcha可以有效地防止恶意攻击,如暴力破解、SQL注入等网络攻击。

react的滑动图片验证码组件的示例代码

react的滑动图片验证码组件的示例代码

react的滑动图⽚验证码组件的⽰例代码业务需求,需要在系统登陆的时候,使⽤“滑动图⽚验证码”,来验证操作的不是机器⼈。

效果图使⽤⽅式在⼀般的页⾯组件引⽤即可。

onReload这个函数⼀般是⽤来请求后台图⽚的。

class App extends Component {state = {url: ""}componentDidMount() {this.setState({ url: getImage() })}onReload = () => {this.setState({ url: getImage() })}render() {return (<div><ImageCodeimageUrl={this.state.url}onReload={this.onReload}onMatch={() => {console.log("code is match")}}/></div>)}}上代码// index.js/*** @name ImageCode* @desc 滑动拼图验证* @author darcrand* @version 2019-02-26** @param {String} imageUrl 图⽚的路径* @param {Number} imageWidth 展⽰图⽚的宽带* @param {Number} imageHeight 展⽰图⽚的⾼带* @param {Number} fragmentSize 滑动图⽚的尺⼨* @param {Function} onReload 当点击'重新验证'时执⾏的函数* @param {Function} onMath 匹配成功时执⾏的函数* @param {Function} onError 匹配失败时执⾏的函数*/import React from "react"import "./styles.css"const icoSuccess = require("./icons/success.png")const icoError = require("./icons/error.png")const icoReload = require("./icons/reload.png")const icoSlider = require("./icons/slider.png")const STATUS_LOADING = 0 // 还没有图⽚const STATUS_READY = 1 // 图⽚渲染完成,可以开始滑动const STATUS_MATCH = 2 // 图⽚位置匹配成功const STATUS_ERROR = 3 // 图⽚位置匹配失败const arrTips = [{ ico: icoSuccess, text: "匹配成功" }, { ico: icoError, text: "匹配失败" }] // ⽣成裁剪路径function createClipPath(ctx, size = 100, styleIndex = 0) {const styles = [[0, 0, 0, 0],[0, 0, 0, 1],[0, 0, 1, 0],[0, 0, 1, 1],[0, 1, 0, 0],[0, 1, 0, 1],[0, 1, 1, 0],[0, 1, 1, 1],[1, 0, 0, 0],[1, 0, 0, 1],[1, 0, 1, 0],[1, 0, 1, 1],[1, 1, 0, 0],[1, 1, 0, 1],[1, 1, 1, 0],[1, 1, 1, 1]]const style = styles[styleIndex]const r = 0.1 * sizectx.save()ctx.beginPath()// leftctx.moveTo(r, r)ctx.lineTo(r, 0.5 * size - r)ctx.arc(r, 0.5 * size, r, 1.5 * Math.PI, 0.5 * Math.PI, style[0])ctx.lineTo(r, size - r)// bottomctx.lineTo(0.5 * size - r, size - r)ctx.arc(0.5 * size, size - r, r, Math.PI, 0, style[1])ctx.lineTo(size - r, size - r)// rightctx.lineTo(size - r, 0.5 * size + r)ctx.arc(size - r, 0.5 * size, r, 0.5 * Math.PI, 1.5 * Math.PI, style[2])ctx.lineTo(size - r, r)// topctx.lineTo(0.5 * size + r, r)ctx.arc(0.5 * size, r, r, 0, Math.PI, style[3])ctx.lineTo(r, r)ctx.clip()ctx.closePath()}class ImageCode extends ponent {static defaultProps = {imageUrl: "",imageWidth: 500,imageHeight: 300,fragmentSize: 80,onReload: () => {},onMatch: () => {},onError: () => {}}state = {isMovable: false,offsetX: 0, //图⽚截取的xoffsetY: 0, //图⽚截取的ystartX: 0, // 开始滑动的 xoldX: 0,currX: 0, // 滑块当前 x,status: STATUS_LOADING,showTips: false,tipsIndex: 0}componentDidUpdate(prevProps) {// 当⽗组件传⼊新的图⽚后,开始渲染if (!!this.props.imageUrl && prevProps.imageUrl !== this.props.imageUrl) {this.renderImage()}}renderImage = () => {// 初始化状态this.setState({ status: STATUS_LOADING })// 创建⼀个图⽚对象,主要⽤于canvas.context.drawImage()const objImage = new Image()objImage.addEventListener("load", () => {const { imageWidth, imageHeight, fragmentSize } = this.props// 先获取两个ctxconst ctxShadow = this.refs.shadowCanvas.getContext("2d")const ctxFragment = this.refs.fragmentCanvas.getContext("2d")// 让两个ctx拥有同样的裁剪路径(可滑动⼩块的轮廓)const styleIndex = Math.floor(Math.random() * 16)createClipPath(ctxShadow, fragmentSize, styleIndex)createClipPath(ctxFragment, fragmentSize, styleIndex)// 随机⽣成裁剪图⽚的开始坐标const clipX = Math.floor(fragmentSize + (imageWidth - 2 * fragmentSize) * Math.random())const clipY = Math.floor((imageHeight - fragmentSize) * Math.random())// 让⼩块绘制出被裁剪的部分ctxFragment.drawImage(objImage, clipX, clipY, fragmentSize, fragmentSize, 0, 0, fragmentSize, fragmentSize) // 让阴影canvas带上阴影效果ctxShadow.fillStyle = "rgba(0, 0, 0, 0.5)"ctxShadow.fill()// 恢复画布状态ctxShadow.restore()ctxFragment.restore()// 设置裁剪⼩块的位置this.setState({ offsetX: clipX, offsetY: clipY })// 修改状态this.setState({ status: STATUS_READY })})objImage.src = this.props.imageUrl}onMoveStart = e => {if (this.state.status !== STATUS_READY) {return}// 记录滑动开始时的绝对坐标xthis.setState({ isMovable: true, startX: e.clientX })}onMoving = e => {if (this.state.status !== STATUS_READY || !this.state.isMovable) {return}const distance = e.clientX - this.state.startXlet currX = this.state.oldX + distanceconst minX = 0const maxX = this.props.imageWidth - this.props.fragmentSizecurrX = currX < minX ? 0 : currX > maxX ? maxX : currXthis.setState({ currX })}onMoveEnd = () => {if (this.state.status !== STATUS_READY || !this.state.isMovable) {return}// 将旧的固定坐标x更新this.setState(pre => ({ isMovable: false, oldX: pre.currX }))const isMatch = Math.abs(this.state.currX - this.state.offsetX) < 5if (isMatch) {this.setState(pre => ({ status: STATUS_MATCH, currX: pre.offsetX }), this.onShowTips) this.props.onMatch()} else {this.setState({ status: STATUS_ERROR }, () => {this.onReset()this.onShowTips()})this.props.onError()}}onReset = () => {const timer = setTimeout(() => {this.setState({ oldX: 0, currX: 0, status: STATUS_READY })clearTimeout(timer)}, 1000)}onReload = () => {if (this.state.status !== STATUS_READY && this.state.status !== STATUS_MATCH) { return}const ctxShadow = this.refs.shadowCanvas.getContext("2d")const ctxFragment = this.refs.fragmentCanvas.getContext("2d")// 清空画布ctxShadow.clearRect(0, 0, this.props.fragmentSize, this.props.fragmentSize)ctxFragment.clearRect(0, 0, this.props.fragmentSize, this.props.fragmentSize)this.setState({isMovable: false,offsetX: 0, //图⽚截取的xoffsetY: 0, //图⽚截取的ystartX: 0, // 开始滑动的 xoldX: 0,currX: 0, // 滑块当前 x,status: STATUS_LOADING},this.props.onReload)}onShowTips = () => {if (this.state.showTips) {return}const tipsIndex = this.state.status === STATUS_MATCH ? 0 : 1this.setState({ showTips: true, tipsIndex })const timer = setTimeout(() => {this.setState({ showTips: false })clearTimeout(timer)}, 2000)}render() {const { imageUrl, imageWidth, imageHeight, fragmentSize } = this.propsconst { offsetX, offsetY, currX, showTips, tipsIndex } = this.stateconst tips = arrTips[tipsIndex]return (<div className="image-code" style={{ width: imageWidth }}><div className="image-container" style={{ height: imageHeight, backgroundImage: `url("${imageUrl}")` }}> <canvasref="shadowCanvas"className="canvas"width={fragmentSize}height={fragmentSize}style={{ left: offsetX + "px", top: offsetY + "px" }}/><canvasref="fragmentCanvas"className="canvas"width={fragmentSize}height={fragmentSize}style={{ top: offsetY + "px", left: currX + "px" }}/><div className={showTips ? "tips-container--active" : "tips-container"}><i className="tips-ico" style={{ backgroundImage: `url("${tips.ico}")` }} /><span className="tips-text">{tips.text}</span></div></div><div className="reload-container"><div className="reload-wrapper" onClick={this.onReload}><i className="reload-ico" style={{ backgroundImage: `url("${icoReload}")` }} /><span className="reload-tips">刷新验证</span></div></div><div className="slider-wrpper" onMouseMove={this.onMoving} onMouseLeave={this.onMoveEnd}><div className="slider-bar">按住滑块,拖动完成拼图</div><divclassName="slider-button"onMouseDown={this.onMoveStart}onMouseUp={this.onMoveEnd}style={{ left: currX + "px", backgroundImage: `url("${icoSlider}")` }}/></div></div>)}}export default ImageCode// styles.css.image-code {padding: 10px;user-select: none;}.image-container {position: relative;background-color: #ddd;}.canvas {position: absolute;top: 0;left: 0;}.reload-container {margin: 20px 0;}.reload-wrapper {display: inline-flex;align-items: center;cursor: pointer;}.reload-ico {width: 20px;height: 20px;margin-right: 10px;background: center/cover no-repeat;}.reload-tips {font-size: 14px;color: #666;}.slider-wrpper {position: relative;margin: 10px 0;}.slider-bar {padding: 10px;font-size: 14px;text-align: center;color: #999;background-color: #ddd;}.slider-button {position: absolute;top: 50%;left: 0;width: 50px;height: 50px;border-radius: 25px;transform: translateY(-50%);cursor: pointer;background: #fff center/80% 80% no-repeat;box-shadow: 0 2px 10px 0 #333;}/* 提⽰信息 */.tips-container,.tips-container--active {position: absolute;top: 50%;left: 50%;display: flex;align-items: center;padding: 10px;transform: translate(-50%, -50%);transition: all 0.25s;background: #fff;border-radius: 5px;visibility: hidden;opacity: 0;}.tips-container--active {visibility: visible;opacity: 1;}.tips-ico {width: 20px;height: 20px;margin-right: 10px;background: center/cover no-repeat;}.tips-text {color: #666;}以上就是本⽂的全部内容,希望对⼤家的学习有所帮助,也希望⼤家多多⽀持。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

下面给大家介绍一个最容易使用的验证码控件CheckBot。

为吗说是最容易使用呢,因为我看到过的验证码控件都需要在IIS上做不少设置,或者还要拷贝一些特殊的文件到特定的目录,而且验证码图像与输入验证码的输入框外观设置起来也很麻烦(甚至你根本没法设置),而CheckBot则象标准控件一样,无需任何设置,而外观设置则遵循标准控件的统一标准。

让我来演示一下,首先你要把它放到工具箱里去,你要下载那个dll文件(/gugu2000cec里去找找看),然后在工具箱上点右键,然后点浏览选择下载的dll文件,然后CheckBot就应该+到你的工具箱了去了。

新建1个apsnet页,把CheckBot拖过去,你看到的应该是只是一个小图片,而没有收集用户输入的输入框。

验证码的图像和验证码输入框是分离的,这样设计的好处是很方便设置验证码这2部分的布局,你可以关联页面上任何一个可以收集用户输入文字的控件作为验证码输入框。

下面我说说如何让CheckBot关联一个收集用户输入文字的控件作为验证码输入框,现拖一个TextBox控件到页面上,然后查看CheckBot的属性窗口中的ControlForUserType 属性,这是一个下拉框,点击一下,你就可以看到刚刚拖出来的TextBox控件就在列表里,实际上这个列表列出了页面上全部可以做为验证码输入框的控件。

这样第1步就设置完成了,你可以点下F5看到效果了。

是不是很容易呢,验证用户输入是否正确也很容易,下一步再拖一个Button到页面上,双击他跳转到它的处理程序,假设添加的CheckBot控件的ID为CheckBot1,添加这句代码 Response.Write(CheckBot1.Validate());然后再按F5运行,当你在输入框中输入正确的验证码时,点击了Button会输出True,如果写错了,当然会输出False,也许你已经明白了,在代码中调用CheckBot1.Validate()就可以获得用户输入的验证码是否匹配。

通过上边的介绍,你是否也同意CheckBot很容易使用呢,实际上CheckBot不仅容易使用,而且很容易扩展,还方便部署,下边现给打家介绍下如何扩展验证码的绘制。

让我猜下你刚刚对CheckBot的感受,第1是它的确挺容易的,第2应该是它画出来的验证码图像太搓了吧,-_-!!真是不好意思,我还没找到个画验证码好法子,不过你完全可以方便的用你自己的方法来画验证码。

到刚才的页面去,双击下验证码图像,出现了protected void CheckBot1_DrawText(object sender, Gugu.CheckBotComponent.CheckBotDrawTextEventArgs e){},在这个事件里你可以画验证码,事件参数e中包括了画验证码所必需的所有参数,e.Text就是要画的验证码文字,e.Graphics是绘图环境上下文,e.Graphics.DrawString()方法是很便利使用的,e.Rectangle 则描绘了绘图表面的大小,还有些别的参数你可以从属性窗口查一下描述,相信你一定能画个比我强的多的验证码。

最后要提醒一下,CheckBot控件无法获知是否你在这个事件里什么也没做,如果真是那样,验证码图像会变成个全黑的图片,如果你想让其还原,则需要把刚才处理CheckBot1_DrawImageText()这个事件的代码全部删除。

既然画验证码的方法可以自己定制,那么验证码的中文字是否也可以自己定制呢?那是当然的了,CheckBot.ImageText属性就是验证码中将绘制的文字,你可以用自己的方法每次赋一个随机的字符串值,千万别总是赋一个固定值给它,如果那样每次验证码的文字都一样啦。

CheckBot.ImageText属性的默认值为null,在其设置为null的情况下,CheckBot会自动生成随机的文字。

上边我说了CheckBot有一个DrawText事件,实际是CheckBot还有另外一个事件:PreDrawText。

为吗CheckBot需要2个事件呢?这和CheckBot的工作原理是分不开的。

我们知道1次Http请求,只能得到一种类型的Meta类型的回复,像输入框这种元素,是文本类型的,而验证码的图片,则是图像类型的,2者的类型不一样,所以一个完整的验证码不能够用1次Http请求完成,实际上是2次。

第1次请求获得输入框和第2次请求的参数,第2次请求获得验证码图像。

为了把第2次请求时页面不用处理的数据减到最小,在CheckBot 的初始化过程中,CheckBot就完成了画图并把页面终止,所以写在其他位置的代码还没有执行,页面就结束了。

但是在第2次请求图像,CheckBot画图前会先后触发PreDrawText和DrawText2个事件,你可以在这个最后时刻做一些工作。

那么在PreDrawText中都可以做些啥工作呢?修改CheckBot.Drawer属性,Drawer是实现了Gugu.CheckBotComponent.ICheckBotDrawer接口的一个类,实现这个接口的类都要实现DrawText()方法,而此方法可以实现一个画验证码的引擎。

这样,你可以把画验证码的引擎的代码与页面的代码分离,可以放到某一个模块里,或者来自另一个程序集。

请注意:如果你想让刚刚在PreDrawText中赋值的CheckBot.Draw属性起作用,那一个不要截获DrawText 事件,因为如果DrawText事件的监听不为空,CheckBot就会认为你要自己手动来画验证码,那么就会忽略CheckBot.Draw属性。

前边刚给大家介绍了CheckBot的一个主要组件:CheckBot.Draw,实际CheckBot共有4个主要组件,另3个分别是CheckBot.Manager,CheckBot.Generator,CheckBot1.UrlCodes,这4部分都是可以分别订制,从而扩展你的验证码控件。

CheckBot.Manager是用来生成随机的验证码文字的,CheckBot1.UrlCodes则管理者着验证码图像中的参数的编码,从而实现第1次和第2次Http请求之间的信息交换,你可以随时用分别实现了Gugu.CheckBotComponent.ICheckBotGenerator接口和Gugu.CheckBotComponent.CheckBotUrlCodes接口的类更改验证码的行为方式。

CheckBot.Draw是画验证码的引擎。

最后CheckBot.Manager是最复杂的一个,它用来保存验证码的秘密,使客户端的计算机无法识别,同样对CheckBot.Manager属性的更改也有一点特殊的要求,因为第2次请求中画验证码图像是在init初始化中就完成了,所以要想更改CheckBot.Manager属性,必须在init事件之前完成,所以如果要更改CheckBot.Manager属性,务必把它写在Page.PreInint事件中。

CheckBot的确是有很大的灵活性,如果有1天,你在你的站点上很多个不同页面使用了CheckBot,但是某1天发现了有人写了1个更好的验证码画图引擎,并发布为了一个程序集dll文件,你想立即把站点上的所有CheckBot都使用新引擎,那么可以高兴得告诉你,你只需要改几个字母,并不需要修改全部这些页面就可以完成这个庞大的工作,CheckBot支持方便的部署。

你可以在站点的web.config文件中的<appSettings>中添加<add key="CheckBotFactoryAssemblyName" value="NewCheckBot"/><add key="CheckBotFactoryAssemblyVersion" value="1.0.0.0"/><add key="CheckBotFactoryClassName" value="MyNameSpace.MyCheckBotFactory"/>这3个参数,这3个参数指定了这个新程序集中实现了Gugu.CheckBotComponent.ICheckBotFactory接口的类,最简单的情况下,就是程序集里只一个实现Gugu.CheckBotComponent.ICheckBotFactory接口的类,这种情况下你只添加<add key="CheckBotFactoryAssemblyName" value="NewCheckBot"/>这一个参数就可以了,在去各个页面看一下验证码,所有页面的验证码图像都已经改变了。

再大家聊聊验证码的细节,验证码的原理是客户发出第1个请求,服务器端生成一个随机字符串,和对应这个字符串的令牌,然后把令牌保存到回送的页面中,同时把令牌编码到第2次请求的Url参数里,这样第1次请求处理完毕,回送的页面包含了令牌和第2次请求的Url 参数,而Url参数里也有同一个令牌;客户端获得第1次请求的回送后就开始第2次请求,服务器端处理第2次请求,并从Url参数里获得令牌,并通过此令牌查询对应的先期生成的字符串,然后画图,并把图像返回客户端;用户识别图像,并填写验证码,然后提交,服务器接受后,根据保存在页面中的令牌再次查询到先期生成的字符串,并与用户输入的进行比较,从而可以判断出用户输入是否正确。

可以看到在整个过程中客户端只获得一个令牌,而这个令牌并不包含对应字符串的任何信息,所以客户端的计算机无法通过令牌来识别验证码,唯一识别验证码的途径是识别第2次返回的图像,如果图像画的足够花里胡哨的话,客户端的计算机又识别不了,只能由人来识别,从而起到了预防机器人的作用。

话虽这么说,可是在服务器端保存1大堆的字符串还是很占资源的啊,所以CheckBot的默认实现并没有在服务器端保存字符串,而是把它加密了放到令牌里去了,这样的好处是解放了服务器,坏处自是不用说,危险重重啊。

不过把秘密放在客户端也不是一无是处,虽然客户端可以拿着这个令牌来冒充,但是我们还是有对付他的方法,方法就是过期。

CheckBot.ExpectantPeriod就是用来设施过期时间的,初始为5分钟。

对CheckBot的默认实现来说就是保存到客户端的令牌只有5分钟的有效期,如果有人拿着一个冒充的令牌大发淫威的话,他只能疯狂5分钟,5分钟后他得再去自己识别另一个图片,所以客户端保存秘密如果受到攻击,最多是个半自动的,而不会是全自动的。

相关文档
最新文档