Я пытаюсь интегрировать ReCaptcha (v3) с формой SvelteKit. Я использую обычное действие формы. Проблема в том, что я не могу понять, как передать токен, сгенерированный ReCaptcha, на серверную часть Sveltekit.
Теоретически это просто: отправьте форму, вызовите ReCaptcha, чтобы получить токен, и добавьте его в данные формы. Однако я не могу понять, как добавить токен в данные формы, поскольку функция, получающая токен, является асинхронной.
Внутри +page.svelte
у меня следующее. Как я могу получить значение токена Recaptcha в функции use:enhance
?
<script>
let token;
function checkCaptcha() {
grecaptcha.ready(function() {
grecaptcha.execute(key, { action: "submit" }).then(function(t) {
token = t;
console.info(token); // this works, we get the token
});
});
}
</script>
<svelte:head>
<script src = "https://www.google.com/recaptcha/api.js?render = {key}" async defer></script>
</svelte:head>
<form method = "POST" use:enhance = {async ({ formData }) => {
checkCaptcha();
formData.append("token", token); // the token doesn't get here
return async ({ result, update }) => {
update();
};
}}>
<!-- form content -->
</form>
Похоже, что предполагаемый подход состоит в том, чтобы предотвратить отправку; Чтобы по-прежнему использовать обычный процесс действия формы SvelteKit, вы можете попытаться инициировать еще одну отправку, как только у вас будет токен.
Что-то в этом роде:
<script>
import { enhance } from '$app/forms';
/** @import { SubmitFunction } from '@sveltejs/kit'; */
let token = null;
/** @type {SubmitFunction} */
const onSubmit = event => {
if (token == null) {
event.cancel();
grecaptcha.ready(async () => {
token = await grecaptcha.execute('...', { action: 'submit' });
setTimeout(() => event.formElement.requestSubmit());
});
return;
}
event.formData.append('token', token);
// [possibly clear token again]
};
</script>
<form method = "post" use:enhance = {onSubmit}>
...
<button>Submit</button>
</form>
(Вам нужно requestSubmit
, а не submit
, чтобы запустить проверку и обработчики событий, подобные тому, который прикреплен enhanced
. setTimeout
может не понадобиться, если библиотека уже откладывает обратный вызов в другой цикл событий.)
Да, это сработало! Спасибо.
У меня нет опыта работы с ReCaptcha, но я сгенерировал токен в функции load(), и он будет сгенерирован и доступен при создании экземпляра вашего компонента/страницы. Или его нужно сначала сгенерировать при отправке формы?