reCAPTCHA是谷歌出品的人机检测服务,可以自动检测应用所处的环境,并根据情况提供一些机器人无法模拟的场景来防止作弊。
准备工作
首先你要有一个谷歌账户并且可以访问谷歌服务。进入reCAPTCHA开发主页,看到有v3和v2版本,这里我们以v2为例。
首先,我们需要去控制台注册API密钥对。然后配置好使用该API密钥对的域名,这里我们使用localhost。
使用默认界面
默认的长这样:
首先,谷歌支持默认交互界面也支持开发自己定义交互界面。无论你打算采用哪种方式都需要一个载体节点。
<div id="grecaptcha"></div>
其次,我们需要引入googleAPI库,然后等待googleAPI代码加载完毕再调用render方法,将API密钥对等配置注入到容器节点中:
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
<script>
const _grecaptcha = (typeof grecaptcha === 'undefined' ? {} : grecaptcha)
_grecaptcha.ready = function (cb) {
if (typeof grecaptcha === 'undefined') {
// window.__grecaptcha_cfg is a global variable that stores reCAPTCHA's
// configuration. By default, any functions listed in its 'fns' property
// are automatically executed when reCAPTCHA loads.
const c = '___grecaptcha_cfg';
const _window = (window);
_window[c] = _window[c] || {};
(_window[c]['fns'] = _window[c]['fns'] || []).push(cb);
} else {
cb();
}
}
_grecaptcha.ready(()=>{
//grecaptcha 是库暴露的全局方法
grecaptcha.render('recaptcha', {
'sitekey' : 'XXXXXXXXXXXXXXX',
callback:(token)=>{
alert(token)
}
});
})
</script>
此时界面应该出来了,如果你足够心细会发现,谷歌已经帮我们做好国际化了,显示的语言会跟浏览器userAgent里的语言设置用户代理设置的语言同步,非常方便。点击就能取到token,发送到服务端进行比对即可。
可能会有人觉得谷歌的节目不好看,想自己搞一个,接下来介绍一下自定义界面的实现。
自定义界面
首先隐藏容器节点,不可见类型render后会返回一个id,开始检测(触发检查)时传入id调用execute方法
<div style="display: none;" id="recaptcha2"></div>
<button id="button">点击我开始人机检查</button>
let widgetId = 0;
_grecaptcha.ready(()=>{
//grecaptcha 是库暴露的全局方法
widgetId = grecaptcha.render('recaptcha', {
'sitekey' : 'XXXXXXXXXXXXXXX',
//此处选择不可见尺寸
size: 'invisible',
callback:(token)=>{
alert(token)
}
});
})
document.querySelector('#button').addEventListener('click',()=>{
grecaptcha.execute(widgetId)
})
即可,然后点击按钮即可执行检查,需要注意的是检查应该仅触发一次,因此按钮并不是一个合适的交互界面形式,这里仅演示自定义界面实现的流程。
封装并处理错误边界
上述代码比较零碎,需要封装一下,然后不是所有人都能访问谷歌服务,因此需要处理一下加载错误的边界。
这里我们使用ts。
- 声明全局变量:
declare let grecaptcha。 - 需要一个确保grecaptcha能够访问的检测方法:
const ensureGrecaptcha = (cb: () => void) => {
if (typeof grecaptcha === 'undefined') {
// window.__grecaptcha_cfg is a global variable that stores reCAPTCHA's
// configuration. By default, any functions listed in its 'fns' property
// are automatically executed when reCAPTCHA loads.
const c = '___grecaptcha_cfg';
const _window = (window as any);
_window[c] = _window[c] || {};
(_window[c]['fns'] = _window[c]['fns'] || []).push(cb);
} else {
cb();
}
}
ensureGrecaptcha(() => {
console.log('可以使用---',grecaptcha)
//开始渲染容器节点...
})
- 在组件内检测可用状态并添加检测状态
//设置三个状态:未知、加载完毕、失败
const testComponent = () => {
const [grecaptchaValid,setGrecaptchaValid] = useState<'undefined'|'loaded'|'failed'>('undefined')
useEffect(() => {
//10s后如果还没有结果则直接判断失败
setTimeout(() => {
setGrecaptchaValid(_prev => {
if (_prev === 'undefined') {
return 'failed'
}
return _prev
})
}, 10000)
ensureGrecaptcha(() => {
setGrecaptchaValid('loaded')
})
},[])
return (
...
{
grecaptchaValid === 'undefined' && '未知'
}
{
grecaptchaValid === 'loaded' && '完毕!!!!'
}
{
grecaptchaValid === 'failed' && '加载失败,执行回退策略或者提醒!!!!'
}
...
)
}