带有 vue-recaptcha-v3 (v1.8.0) 的 reCAPTCHA v3 不断通过提取验证失败 API

reCAPTCHA v3 with vue-recaptcha-v3 (v1.8.0) constantly failing verification with the fetch API

在我的带有节点模块 vue-recaptcha-v3 的 VueJS 应用程序中,reCAPTCHA v3 在验证步骤 中不断失败。 "protected by reCAPTCHA" 横幅按应有的方式出现在页面上,我在验证步骤之前得到的响应很好。当我尝试通过 fetch:

POST 将令牌 https://www.google.com/recaptcha/api/siteverify
// Execute reCAPTCHA with action "login".
const response = await this.$recaptcha('contact');
const data = {
    secret: secretKey,
    response,
};

try {
    const validationResponse = await fetch(validationUrl, {
        method: 'POST',
        headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
        },
        body: JSON.stringify(data),
    });
[...]

我只是得到错误 Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at https://www.google.com/recaptcha/api/siteverify. (Reason: CORS header ‘Access-Control-Allow-Origin’ missing).

所以我用mode: 'no-cors'代替:

[...]
const validationResponse = await fetch(validationUrl, {
    method: 'POST',
    mode: 'no-cors',
    headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json',
    },
    body: JSON.stringify(data),
});
[...]

然后导致此响应:

{
  "success": false,
  "error-codes": [
    "missing-input-response",
    "missing-input-secret"
  ]
}

我想你不能在 no-cors 模式 (https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch#Supplying_request_options) 中发送 json 的内容类型,所以我改用 multipart/form-data 作为内容类型:

const response = await this.$recaptcha('contact');
const formData = new FormData();
formData.append('secret', secret_key);
formData.append('response', response);

try {
    const validationResponse = await fetch(validationUrl, {
        method: 'POST',
        mode: 'no-cors',
        headers: {
            Accept: 'application/json',
            'Content-Type': 'multipart/form-data',
        },
        body: formData,
    });
[...]

但这只会导致 Google 的回应:

<HTML>
<HEAD>
<TITLE>Bad Request</TITLE>
</HEAD>
<BODY BGCOLOR="#FFFFFF" TEXT="#000000">
<H1>Bad Request</H1>
<H2>Error 400</H2>
</BODY>
</HTML>

我真的不知道该怎么办了——我错过了什么?

好的,我终于在 Whosebug 找到了答案: - 长话短说:Googles reCAPTCHA 验证服务器似乎只接受 "Content-Type": "application/x-www-form-urlencoded",所以发送的数据我的情况需要

body: 'secret=' + secretKey + '&response=' + response

使用这些设置不会发生错误(请注意:像这样发送的数据需要通过 URLencode 进行清理!我在这个例子中忽略了它。) 但它仍然令人困惑,例如Firefox 显示来自 Google 的正确响应,但 Vue 应用程序根本无法读取它 - response.ok euqals false!

原因:browser/client本身无法处理no-cors响应。服务器必须这样做!因此必须将 reCAPTCHA 响应发送到您的服务器,并且服务器(例如 PHP)必须将数据发送到 Google 的验证脚本。没有其他办法解决这个问题。 Google reCAPTCHA 的文档遗漏了所有这些要点。

此外 - 令我感到羞耻的是我现在才意识到这一点 - 这完全有道理,因为对于 reCAPTCHA 验证,你需要你的 secret reCAPTCHA 密钥,而那个密钥绝对不应该存储在发送给客户端的 JS 应用程序中。你永远不会泄露你的秘密。