如何在web中使用reCAPTCHA

2,144 阅读3分钟

reCAPTCHA是谷歌出品的人机检测服务,可以自动检测应用所处的环境,并根据情况提供一些机器人无法模拟的场景来防止作弊。

准备工作

首先你要有一个谷歌账户并且可以访问谷歌服务。进入reCAPTCHA开发主页,看到有v3v2版本,这里我们以v2为例。

首先,我们需要去控制台注册API密钥对。然后配置好使用该API密钥对的域名,这里我们使用localhost

image.png

使用默认界面

默认的长这样: image.png

首先,谷歌支持默认交互界面也支持开发自己定义交互界面。无论你打算采用哪种方式都需要一个载体节点。

<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

  1. 声明全局变量:declare let grecaptcha
  2. 需要一个确保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)
    //开始渲染容器节点...
})
  1. 在组件内检测可用状态并添加检测状态
//设置三个状态:未知、加载完毕、失败
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' && '加载失败,执行回退策略或者提醒!!!!'
        }
        ...
    )
}