背景
uni-app 的项目中需要接入极验验证码,根据极验官方文档,只能在微信的 wxml 页面中引入模板,但是对于每个页面都有接口调用的情况下,手动加是不可能的,开发量大,测试工作量也大,需要回归整个app,但是官方也没有提供类似全局api的形式给到 js 去调用,小程序不像H5 是可以临时插入dom进行操作的,所有要做到全局把控,只能通过中间页的形式。
实现思路
思路:通过小程序里面建一个中间页面,在接口响应的时候,根据 code 码跳转到承载极验验证码的页面,在这个页面里面做相关的逻辑处理,成功之后在返回到上一个页面即可。为了不占用主包的大小,所以这个中间页最好放在分包里面。为了保存数据,在页面中使用,可以将数据存在 vuex 中,这样可以全局读取,进行二次验证传递给接口。
实现步骤
申请插件
登陆微信小程序的后台,在设置-第三方服务-插件管理
中添加插件,通过 appid(wxefa63d84fe9f64a2)查找并添加验证码插件,等待极验通过申请即可使用。
插件通过后,可以在微信开发者工具详情-插件信息中查看插件的版本号
配置插件
- 在文件
src/manifest.json
中找到微信相关的配置,加入插件:
"mp-weixin": { /* 微信小程序特有相关 */
"appid": "xx",
"setting": {
"urlCheck": false
},
"usingComponents": true,
"optimization": {
"subPackages": true
},
"plugins": {
"myPlugin": {
"version": "1.3.3",
"provider": "wxefa63d84fe9f64a2"
}
}
},
- 在
src/pages.json
中找到分包subPackages
,加入承载验证码操作的中间页,在这个页面引入插件,就可以在当前页面中使用:
"subPackages": [
"root": "packageSecond",
"pages": [
{
"path": "pages/geetest/geetest",
"style": {
"navigationBarTitleText": "验证码",
"mp-weixin": {
"usingComponents": {
"captcha": "plugin://myPlugin/captcha"
}
}
}
}
]
]
中间页
新建中间页,在分包目录下,如src/packageSecond/pages
下新建一个中间页面geetest/geetest.vue
,页面中引入极验验证码的模板,按照vue的语法转换模板,监听成功和失败的时间,做相应的业务逻辑处理,根据官方文档,微信小程序的模板写法<captcha id="captcha" wx:if="{{loadCaptcha}}" gt="{{gt}}" challenge="{{challenge}}" offline="{{offline}}" bindonSuccess="captchaSuccess" />
wx:if
换成v-if
,{{}}
语法换成 vue 模板语法,事件绑定换成@onSuccess
// geetest/geetest.vue
<template>
<view class="container">
<view class="gettest-box">
<captcha
v-if="geetestObj.loadCaptcha"
:gt="geetestObj.gt"
:challenge="geetestObj.challenge"
:offline="geetestObj.offline"
@onError="error"
@onSuccess="success"
/>
</view>
</view>
</template>
<script>
import { mapState } from 'vuex'
import store from 'store'
export default {
computed: {
...mapState({
geetestObj: state => state.geetestObj,
}),
},
methods: {
error(e) {
console.log('我是挤眼验证码,我出错了')
},
async success(result) {
try {
store.commit('SET_GEETEST_RESULT', result.detail)
const secondVerifyUrl = '/api/secondVerify'
const reportResultUrl = '/api/reportResult'
const options = {stone: true, json: true}
const resultData = result.detail
// 二次验证需要的参数
const secondVerifParams = {
challenge: resultData.geetest_challenge,
serverStatus: this.geetestObj.serverStatus,
validate: resultData.geetest_validate,
seccode: resultData.geetest_seccode,
devicePlatform: 'h5',
}
const secondVerify = await postRequest(secondVerifyUrl, secondVerifParams, options)
let { resultCode = '' } = secondVerify
if (resultCode) {
const params = {
challenge: resultData.geetest_challenge,
serverStatus: this.geetestObj.serverStatus,
result: resultCode === '200' ? 1 : 0,
devicePlatform: 'h5',
}
const reportResult = await postRequest(reportResultUrl, params, options)
if (reportResult.resultCode) {
const pages = getCurrentPages() // 当前页面
const beforePage = pages[pages.length - 2] // 上一页
const options = beforePage.options
uni.navigateBack({
success: function() {
beforePage.onLoad(options) // 执行上一页的onLoad方法
}
})
}
}
} catch(e) {
console.log(e)
}
}
}
}
</script>
<style lang="scss">
.container {
width: 100vw;
height: 100vh;
position: relative;
.gettest-box {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
}
</style>
监听接口
封装好的接口请求中监听响应的状态,将数据存到 store 中,在验证码中间页拿到数据,进行二次验证的时候传给后端接口。
// server.js
fetchInstance.interceptors.response.use(res => {
// #ifdef MP-WEIXIN
if (res.data.status === 485) {
const data = res.data.data
const obj = {
loadCaptcha: data.newCaptcha,
gt: data.gt,
challenge: data.challenge,
offline: !data.serverStatus,
serverStatus: data.serverStatus
}
store.commit('SET_GEETEST_OBJ', obj)
uni.navigateTo({
url: '/packageSecond/pages/geetest/geetest'
})
}
// #endif
})
以上就是接入的这个过程。
效果如下:
参考:
https://docs.geetest.com/sensebot/apirefer/api/miniprogram
https://docs.geetest.com/sensebot/deploy/client/miniprogram
https://uniapp.dcloud.io/component/mp-weixin-plugin