网易云盾使用
日常使用app、web网站登录时,经常会遇到验证码校验问题,传统的验证是让用户输入页面上展示的文本,不仅费时而且对于交互而言并不算友好。在开发过程中使用了网易云盾图形校验,让用户通过滑动的方式来实现安全认证。
1. 定义CstaticdunValidate类
首先我们定义一个工具类来初始化网易云盾
/**
* 1、默认网易云盾智能免验证
* 2、初始化可开启网易云盾非智能免验证
* 在发送短信验证码的场景下使用2,其他的使用1。启用参数:force,布尔值
* 两种验证码唤起方式1:verify(),2: popUp()
*/
class CstaticdunValidate {
constructor(options, onInitCallback, onErrorCallback, force = false) {
this.options = options;
this.onInitCallback = onInitCallback;
this.onErrorCallback = onErrorCallback;
this.force = force;
this.defaultOptions = {
element: '#captcha', // DOM元素
width: 'computed', // 验证按钮宽度
// protocol: 'http', // 验证码传输数据使用的网络协议,默认使用网站协议
lang: 'zh-CN', // 验证码语言选项
onReady: function (instance) {
// 验证码一切准备就绪,此时可以正常使用验证码的功能
},
onVerify: function (err, data) {
// 验证码验证结束回调
},
};
this.init();
}
init() {
let extendOptions;
const _this = this;
if (this.force) { // 强制验证
extendOptions = {
captchaId: 'foo', // 从网易云盾申请captchaId
mode: 'popup' // 从页面上弹出
}
} else { // 智能验证
extendOptions = {
captchaId: 'bar',
mode: 'bind', // 无感知认证
}
}
const formatOptions = Object.assign(this.defaultOptions, this.options, extendOptions);
let computedOptions = null;
if (formatOptions.width === 'computed') {
computedOptions = this.computeWidth(formatOptions);
}
this.options = computedOptions || formatOptions;
window.initNECaptcha && window.initNECaptcha(formatOptions, function onload (instance) {
// 初始化成功
_this.cstaticdun = instance;
_this.onInitCallback && _this.onInitCallback(instance);
}, function onerror (err) {
// 验证码初始化失败处理逻辑
_this.onErrorCallback && _this.onErrorCallback(err);
})
}
computeWidth(formatOptions) {
formatOptions.width = '8rem';
return formatOptions;
}
}
export default CstaticdunValidate;
1.1 mode
上面的代码中我们可以看到定义mode
官方文档中给了几种mode使用方式:
- 常用验证码
- 触发式(float)
- 弹出式(popup)
- 嵌入式(embed)
- 无感知模式
- bind模式(bind)
具体使用官方文档中有给出案例
1.2 onVerify(err, data)
当调用onVerify是,会传入两个参数
- err(Error实例),验证失败才会有error对象
- data: 验证成功后的相关信息,data数据结构为
key-value
格式
2. 定义MontNECaptcha函数
该函数用于在页面渲染时,加载网易云盾的js并进行方法初始化
/**
* 挂载网易云盾插件
* @param callback
*/
const montNECaptcha = (callback) => {
// 如果已经初始化则直接回调成功
// @ts-ignore
if (window.initNECaptcha) {
// @ts-ignore
callback && callback(!!window.initNECaptcha);
return;
}
// @ts-ignore
let captcha;
// 检查是否已经存在元素节点,防止重复添加
const elements = document.querySelector('#NECaptchaJS');
// @ts-ignore
if (!elements) {
captcha = document.createElement('script');
captcha.id = 'NECaptchaJS';
captcha.type = 'text/javascript';
captcha.src = 'https://cstaticdun.126.net/load.min.js' + '?t=' + getTimestamp(10 * 60 * 1000) // 时长1分钟,建议时长分钟级别
const head = document.head || document.getElementsByTagName('head')[0]
head.appendChild(captcha)
} else {
captcha = elements;
}
// 记录元素原本的onload函数
let preOnLoad = captcha.onload;
captcha.onload = function () {
if (preOnLoad) {
// @ts-ignore
preOnLoad(!!window.initNECaptcha);
preOnLoad = null;
}
// @ts-ignore
callback && callback(!!window.initNECaptcha)
callback = null;
}
};
function getTimestamp (msec) {
msec = !msec && msec !== 0 ? msec : 1
return parseInt((new Date()).valueOf() / msec + '', 10)
}
export default plugYunDun
上面的代码中captcha.src = 'https://cstaticdun.126.net/load.min.js'
在页面的<head>
中引入网易云盾的包,后面的?t=
是用来记录时间戳,清除缓存
3. 定义useCstaticdun函数
对以上的代码进行一层封装,这样可以在页面调用时减少代码量
import { useEffect, useRef } from 'react'
import plugYunDun from '@/utils/yunDunUtil'
import StaticdunValidate from '@/utils/cstaticdunValidate'
export interface ICstaticdunProps {
onYunDunVerify: (err, data) => void
}
export default function useCstaticdun(props: ICstaticdunProps) {
const cstaticdunRef = useRef(undefined as any)
const { onYunDunVerify } = props
useEffect(() => {
// 初始化网易云盾
plugYunDun((success) => success && initCstaticdunValidate())
}, [])
/**
* 网易云盾绑定
*/
const initCstaticdunValidate = () => {
new StaticdunValidate(
{
onVerify: onYunDunVerify,
},
(instance) => {
console.warn('NECaptcha has inited')
cstaticdunRef.current = instance
},
(err) => {
console.log(err)
},
)
}
const refresh = (callback?) => {
cstaticdunRef.current.refresh()
setTimeout(() => {
cstaticdunRef.current && cstaticdunRef.current.verify()
callback && callback()
}, 250)
}
return {
cstaticdunRef,
cstaticdunRefresh: refresh,
}
}
4. 页面中使用
const onYunDunVerify = (err, data) => {
if (!err) {
const params = {
policyIdEn,
captchaId: cstaticdunRef.current.captchaId,
validate: data.validate,
simpleCardNo: idCardRef.current
}
AuthRequest.certificateVerification(params).then((res) => {
const result = plainToClass(BaseResponse, res)
// do something
}).catch((res: BaseResponse) => {
// do something
})
}
}
const {cstaticdunRef, cstaticdunRefresh} = useCstaticdun({onYunDunVerify})