人机交互校验介绍
极验是一款人机交互页面效果系统,用户的行为没有满足要求,不给与下一步执行的机会
大致效果如下,用户如果没有把目标滑到指定区域就禁止下一步操作
这种小功能,在我们体验一个网站的时候是经常遇见的,在之前的传统网站中,用户输入用户名,密码,验证码就可以登录系统了,但是这样的网站不安全,有网络爬虫技术,可以通过“后端程序代码” 模拟账号登录,进而获得我们网站的信息
现在比较先进的网站,都使用“人机交互验证”功能,对登录者提出高要求,不让模拟登录得逞,相反只允许“实在的人”来登录系统并应用
这里我们主要使用的是极验的功能 极验官网:www.geetest.com/
这样做额好处就是防止账号暴力破解,不给模拟登录机会,增加系统的安全性
获取并导入js脚本
1. 获取好的gt.js文件放到 src/assets/js 目录下
2. 对不遵守eslint规范的代码稍加改动
eslint标准规范中有如下要求:
- 函数传递参数,不能直接传递boolean值,相反可以声明变量传递(gt.js文件中一共有4处,注意调整)
- 要通过 “===”恒等于 方式 判断两个字是否相等(上例为了使得数据类型是严格的字符串,额外调用了toString()方法,请注意)
- 不要设置空的回调函数实参,没有意义
开发步骤
人机交互验证开发流程:
- axios向本身后端服务器发起请求,后端服务器会返回极验请求的秘钥信息
- 极验秘钥信息 + 用户行为 一并提交给 极验服务器 做判断,查验行为是否正确
methods: {
login () {
this.$refs.loginFormRef.validate(valid => {
// 表单域校验成功
if (valid) {
// A. axios获得极验请求秘钥信息
let pro = this.$http.get(`/captchas/${this.loginForm.mobile}`)
pro
.then(result => {
// 服务器端返回极验的请求秘钥信息
console.log(result) // config 【data】 request headers status statusText
})
.catch(err => {
return this.$message.error('获得极验初始校验信息错误:' + err)
})
// B. 账号真实校验,登录后台
// this.loginAct()
}
})
},
// 校验账号真实性,登录后台
loginAct () {
// 账号真实性校验
var pro = this.$http.post('/authorizations', this.loginForm)
pro
.then(result => {
if (result.data.message === 'OK') {
// 客户端记录用户的信息
window.sessionStorage.setItem('userinfo', JSON.stringify(result.data.data))
// 进入后台系统
this.$router.push('/home')
}
})
.catch(err => {
return this.$message.error('用户名或密码错误' + err)
})
}
}
创建窗口并应用
- 在login/index.vue中向引入gt.js文件
- 对返回的极验请求秘钥信息做接收处理(对象解构赋值)
- 调用initGeetest() 函数,生成极验窗口
- 添加product:'bind'
- verify()等方法调用
// 对gt.js文件进行导入
// gt.js文件本身没有做导出动作,所以就直接导入即可,此时系统增加一个全局变量,名称为 initGeeTest
import '@/assets/js/gt.js'
……
login () {
this.$refs.loginFormRef.validate(valid => {
// 表单域校验成功
if (valid) {
// A. axios获得极验初始校验信息
let pro = this.$http.get(`/captchas/${this.loginForm.mobile}`)
pro
.then(result => {
// 接收处理返回的极验请求秘钥信息
let { data } = result.data
// 显示极验应用窗口
// 请检测data的数据结构, 保证data.gt, data.challenge, data.success有值
window.initGeetest({
// 以下配置参数来自服务端 SDK
gt: data.gt,
challenge: data.challenge,
offline: !data.success,
new_captcha: true,
product: 'bind' // 没有按钮,通过登录按钮激活验证
}, captchaObj => {
// 这里可以调用验证实例 captchaObj 的实例方法
captchaObj.onReady(() => {
// 验证码ready之后才能调用verify方法显示验证码
captchaObj.verify() // 显示验证码窗口
}).onSuccess(() => {
// your code
// B. 校验账号真实性,登录
this.loginAct()
}).onError(() => {
// your code
})
})
})
.catch(err => {
return this.$message.error('获得极验初始校验信息错误:' + err)
})
}
})
},
注意:在原来的配置参数中initGeetest()函数不加window的,但是由于是在Vue实例中使用,在这里未定义,所以不能使用,
我们观察gt.js文件可以知道,在gt.js文件中已经给他挂载成了全局变量,把他挂载到了window身上,如果我们想使用的话,需要使用window来调用这个函数
以上我们的基本功能已经基本实现,但是我们可以发现点击登录之后,窗口不能马上显示,在此期间设置按钮等待效果
极验窗口的显示需要消耗一定时间,为了增强用户体验,给“登录”按钮设置“等待”效果,同时考虑到严谨性,要同时设置disabled,使得按钮等待的同时也不让单击
<el-button :loading="ture/false" :disabled="true/false">登录</el-button>
步骤
1.data成员设置 isActive:false
isActive: false, // 按钮是否等待、禁用
2.给el-button登录按钮应用 loading 和 disabled属性,它们的值通过 btnLoading控制
<el-button
style="width:100%;"
:loading="isActive"
:disabled="isActive"
type="primary"
@click="login()">登录</el-button>
3.单击登录按钮后马上禁用 按钮 this.isActive= true
login () {
this.$refs.loginFormRef.validate(valid => {
// 表单域校验成功
if (valid) {
this.isActive = true // 登录按钮处于等待、禁用状态
4.极验交互窗口显示完毕 就恢复按钮 this.isActive= false
captchaObj.onReady(() => {
……
this.isActive = false // 恢复按钮
当我们实现了按钮的切换之后,我们发现在用户重复点价之后,会创建多个DOM元素,这里我们对他进行一个优化处理,也就是使得用户多次点击登录按钮,关于验证窗口只生成一份
优化处理:
第一次生成人机窗口后,就给保存起来,后续再发生相同的动作直接使用即可
好处:用户等待时间缩短,页面上也不用生成许多div了
步骤
1.创建data成员 ctaObj
ctaObj: null, // 极验对象
2.第一次生成的人机窗口对象 赋予给 this.ctaObj= captchaObj
captchaObj.onReady(() => {
……
this.ctaObj = captchaObj // 已经极验对象赋予给ctaObj
3.用户重复单击登录窗口使用缓存好的极验对象
login () {
this.$refs.loginFormRef.validate(valid => {
// 表单域校验成功
if (valid) {
// 极验对象存在就直接调用
if (this.ctaObj !== null) {
return this.ctaObj.verify()
}
// 注意:按钮等待 要在 之后设置
this.isActive = true // 登录按钮处于等待、禁用状态
注意:
登录按钮等待的代码要在之后设置,这样的原因是使用之前的缓存极验对象,由于速度很快,按钮就不要做禁用状态了