200行代码实现解锁滑动验证码(文末附源码)
The following article is from 进击的Coder Author 崔庆才
作者:崔庆才转自:进击的coder做网络爬虫的同学肯定见过各种各样的验证码,比较高级的有滑动、点选等样式,看起来好像挺复杂的,但实际上它们的核心原理还是还是很清晰的,本文章大致说明下这些验证码的原理以及带大家实现一个滑动验证码。我之前做过 Web 相关开发,尝试对接过 Lavavel 的极验验证,当时还开发了一个 Lavavel 包:https://github.com/Germey/LaravelGeetest,在开发包的过程中了解到了验证码的两步校验规则。实际上这类验证码的校验是分为两个步骤的:
第一步就是前端的校验。一般来说,登录注册页面在点击提交的时候都会伴随着一个表单提交,在表单提交的时候会有 JavaScript 事件的触发。如果加入了验证码,那么在表单提交的时候会多加一个额外的验证,判断这个验证码是否已经成功完成了操作。如果没有的话,那就直接取消表单的提交,然后顺便提示说”您的验证没通过,请重新验证“,诸如此类的话。所以这一步就能防范”君子“之为了。
第二步就是服务端的校验。意思就是说表单提交之后,会有请求发送到服务器,这个请求中包含了很多数据,比如用户名、密码,如果对接了验证码的话,还会有额外的验证码的值,或者更复杂的加密后的 Token 值,服务器会对发过来的信息进行校验,如果验证通过,那么整个请求就成功了,返回正常的响应,否则返回错误的响应。所以如果想要通过程序来直接构造表单提交的时候,服务端就可以做进一步的校验,由于提交的验证码相关的信息都是和服务端的 Session 相关联的,另外再加上一些 CSRF 等的校验,所以这一步就能防范”小人“之为了。
需求
那么前端完成一个合格的验证码,究竟需要做成什么样子呢?首先验证码有个大体的雏形,既然是拖动验证码,那就要拖动块和目标块,我们需要把拖动块拖动到目标块上就算校验成功。
验证码的一个功能就是来规避机器的自动操作,所以我们需要通过轨迹来判断这个拖动过程是真实的人还是机器,因此我们需要记录拖动的路径,路径经过计算之后可以发送到后端进行进一步的分类,比如对接深度学习模型来分类拖动轨迹是否是人。
结果
这里就先给大家看看结果吧:具体实现
下面就具体讲解下这个是怎么实现的,实际上核心代码只有 200 行,下面对整个核心流程进行说明。既然 Vue 这么火,那我这里就用 Vue 来实现啦,具体的环境配置这里就不再赘述了,需要安装的有:Node.js:https://nodejs.org/en/
Vue-Cli:https://cli.vuejs.org/zh/
<div id="app">
<div id="wrapper" :style="wrapperStyle">
<drop class="drop" id="target"
:class="{ 'over': state.over }"
@dragover="onDragOver"
@dragleave="onDragLeave"
:style="targetStyle">
</drop>
<drag class="drag" id="source"
:transfer-data="true"
@dragstart="onDragStart"
@dragend="onDragEnd"
@drag="onDrag" v-if="!state.dragged"
:style="sourceStyle">
<div slot="image" id="float" :style="sourceStyle">
</div>
</drag>
</div>
</div>
</template>
Drop
对于 Drop 组件来说,它是一个被放置的对象,被拖动滑块会放到这个 Drop 滑块上,这就代表拖动成功了。它有两个主要的事件需要监听,一个叫做 dragover,一个叫做 dragleave,分别用来监听 Drag 对象拖上和拖开的事件。在这里,分别对两个事件设置了 onDragOver 和 onDragLeave 的回调函数,当 Drag 对象放到 Drop 对象上面的时候,就会触发 onDragOver 对象,当拖开的时候就会触发 onDragLeave 事件。那这样的话我们只需要一个全局变量来记录是否已经将滑块拖动到目标位置即可,比如可以定一个全局变量 state,我们用 over 属性来代表是否拖动到目标位置。因此 onDragOver 和 onDragLeave 事件可以这么实现:this.state.over = true
},
onDragLeave() {
this.state.over = false
}
Drag
对于 Drag 组件来说,它是一个被拖动的对象,我们需要将这个 Drag 滑块拖动到 Drop 滑块上,就代表拖动成功了。它有三个主要的时间需要监听:dragstart、drag、dragend,分别代表拖动开始、拖动中、拖动结束三个事件,我们这里也分别设置了三个回调方法 onDragStart、onDrag、onDragEnd。对于 onDragStart 方法来说,应该怎么实现呢?这里应该处理刚拖动的一瞬间的动作,由于我们需要记录拖动的轨迹,所以声明一个 trace 全局变量来保存轨迹信息,onDragStart 要做的就是初始化 trace 对象为空,另外记录一下初始的拖动位置,以便后续计算拖动路径,所以可以实现如下:this.init = {
x: event.offsetX,
y: event.offsetY,
}
this.trace = []
}
let offsetX = event.offsetX - this.init.x
let offsetY = event.offsetY - this.init.y
this.trace.push({
x: offsetX,
y: offsetY,
})
}
if (this.state.over) {
this.state.dragging = false
this.state.dragged = true
this.$message.success('拖动成功')
}
else {
this.state.dragging = false
this.state.dragged = false
this.$message.error('拖动失败')
}
this.state.over = false
}
return {
width: this.size.width + 'px',
height: this.size.height + 'px',
backgroundImage: 'url(' + this.image + ')',
backgroundSize: 'cover'
}
},
targetStyle() {
return {
left: this.block.x + 'px',
top: this.block.y + 'px'
}
},
sourceStyle() {
return {
backgroundImage: 'url(' + this.image + ')',
backgroundSize: this.size.width + 'px ' + this.size.height + 'px',
backgroundPosition: -this.block.x + 'px ' + -this.block.y + 'px'
}
}
<p v-if="state.dragged" id="trace">
拖动轨迹:{{ trace }}
</p>
</div>
/ 上期中奖者公布 /☞ 混脸熟赠书规则恭喜平凡中的不平凡同学上期走心留言中奖,获取《机器学习线性代数基础-Python语言描述》书籍一本,请联系小编获取,微信:lucici1990
推荐阅读
2、80页笔记看遍机器学习基本概念、算法、模型,帮新手少走弯路
5、2019互联网月饼哪家强?阿里走情怀;百度最土豪!
👆关注“数据挖掘工程师”