期望的行为
将reCaptcha JavaScript代码整合到我的webpack捆绑的js文件中,而不是通过内嵌脚本标签。
实际行为
我在Chrome开发工具中遇到此错误:
未捕获的ReferenceError:未定义grecaptcha
我尝试过的事情
以下inline
的实现工作正常,我一直在使用these docs for reference。
但是,我必须将unsafe-inline
添加到我的script-src
内容安全策略中,才能运行内联脚本。更具体地说,这是通过onLoadCallback
函数实现explicit rendering所必需的。
Google有一个FAQ about CSP and reCaptcha,但仅适用于automatic rendering,那里没有回调函数或defined parameters。
我不想不必使用内联脚本。
index.html
<head>
<script type="text/javascript">
var onloadCallback = function() {
grecaptcha.render('g-recaptcha', {
'sitekey': '******',
'size': 'compact'
});
};
</script>
</head>
<body>
<div id="g-recaptcha"></div>
<script src="https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit" async defer></script>
</body>
</html>
但是,当我尝试像这样将JS添加到我的entry.js
文件中时(停止使用内联脚本):
index.html
<head>
<script type="module" src="/js/bundle.js"></script>
<script src="https://www.google.com/recaptcha/api.js?render=explicit" async defer></script>
</head>
<body>
<div id="g-recaptcha"></div>
</body>
</html>
entry.js
const onloadCallback = () => {
grecaptcha.render('g-recaptcha', {
'sitekey': '******',
'size': 'compact',
'data-callback': 'ok-you-can-submit-the-form',
'data-expired-callback': 'you-have-to-click-recaptcha-again',
'data-error-callback': 'something-went-wrong-please-try-again'
});
}
$(document).ready(function() {
onloadCallback();
}
我在Chrome开发工具中收到错误:
未捕获的ReferenceError:未定义grecaptcha
所以我想这是因为bundle.js
不了解<head>
部分中定义的Recaptcha脚本或其相关变量。
如何在不使用嵌入式脚本范例的情况下实现google reCaptcha?
修改
我认为Google建议使用nonce-based approach(也在this SO answer中建议)仅在您进行automatic rendering(仅需要<script src="****">
标记)的情况下有效。
如果您原样使用explicit rendering,则需要内联定义回调函数,那么我认为现时方法不起作用。
答案 0 :(得分:1)
只需发布最终对我有用的内容即可。
使用reCAPTCHA v3。
index.html
头:
<script src="https://www.google.com/recaptcha/api.js?render=*******"></script>
点击事件:
grecaptcha.ready(function() {
grecaptcha.execute('*******', { action: 'submit_entry' }).then(function(token) {
parameters.token = token;
ajax_api_entries_post(parameters);
});
});
从服务器验证Google令牌:
var token = req.body.token;
var url = `https://www.google.com/recaptcha/api/siteverify?secret=${secret_key}&response=${token}`;
var response = await fetch(url);
var response_json = await response.json();
var score = response_json.score;
// see: https://developers.google.com/recaptcha/docs/v3#interpreting_the_score
if (score >= 0.5) { ...
helmet配置:
app.use(
helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
scriptSrc: ["'self'", "https://maps.googleapis.com", "https://www.google.com", "https://www.gstatic.com"],
connectSrc: ["'self'", "https://some-domain.com", "https://some.other.domain.com"],
styleSrc: ["'self'", "fonts.googleapis.com", "'unsafe-inline'"],
fontSrc: ["'self'", "fonts.gstatic.com"],
imgSrc: ["'self'", "https://maps.gstatic.com", "https://maps.googleapis.com", "data:", "https://another-domain.com"],
frameSrc: ["'self'", "https://www.google.com"]
}
},
})
);