在逛 CloudFlare 的时候看到了 Turnstile,觉得好奇就去看了下文档才知道它是 CloudFlare 家的人机验证,刚好部署了图床管理就想着能不能试试接入它,做下记录。

1. 创建 Turnstile 组件

在 src/components 目录中创建一个新的 Turnstile 组件,比如 Turnstile.vue

<template>
  <div>
    <div id="cf-turnstile" :data-sitekey="siteKey"></div>
  </div>
</template>

<script setup lang="ts">
import {onMounted, ref} from "vue";

const props = defineProps<{
  sitekey: {
    type: String,
    required: true
  }
}>()

const turnstileResponse = ref<string>('')
const emit = defineEmits(['getTurnstileResponse'])

onMounted(() => {
  loadTurnstileScript()
})

const loadTurnstileScript = () => {
  const script = document.createElement('script');
  script.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js?onload=onloadTurnstileCallback';
  script.async = true;
  script.defer = true;
  document.head.appendChild(script);

  script.onload = () => {
    setupTurnstileCallback();
  };
}

const setupTurnstileCallback = () => {
  window.onloadTurnstileCallback = () => {
    window.turnstile?.render("#cf-turnstile", {
      sitekey: props.sitekey,
      callback: handleTurnstileSuccess
    });
  };
}

const handleTurnstileSuccess = (token: String) => {
  turnstileResponse.value = token
  emit('getTurnstileResponse', turnstileResponse)
}
</script>

<style scoped>
</style>

2. 使用 Turnstile 组件并验证响应

在你的主组件(例如 App.vue 或者其他组件)中使用 Turnstile 组件,并处理表单提交和 Turnstile 验证:

<template>
  <div id="app">
    <form @submit.prevent="handleSubmit">
      <Turnstile @getTurnstileResponse="getTurnstileResponse" :siteKey="siteKey" />
      <button type="submit">Submit</button>
    </form>
  </div>
</template>

<script>
import axios from 'axios';
import Turnstile from './components/Turnstile.vue';

const siteKey = ref('your-site-key')
// 获取子组件值
const turnstileResponse = ref<string>('')
const getTurnstileResponse = (value: string) => {
    turnstileResponse.value = value
}

const handleSubmit = () =>  {

    try {
        const response = await axios.post('/verify-turnstile', {
            response: turnstileResponse.value._value
        });

        if (response.data.success) {
            alert('Verification successful!');
        } else {
            alert('Verification failed!');
        }
    } catch (error) {
        console.error('Error during Turnstile verification:', error);
        alert('Verification error!');
    }
}
</script>

3. 服务器端验证 Turnstile 响应

在服务器端处理 Turnstile 响应验证。以下是使用 Node.js 和 Express 的示例:

const express = require('express');
const bodyParser = require('body-parser');
const axios = require('axios');
const app = express();

app.use(bodyParser.json());

app.post('/verify-turnstile', async (req, res) => {
  const turnstileResponse = req.body.response;
  const secretKey = 'your-secret-key';

  try {
    let formData = new FormData();
    formData.append('secret', secretKey);
    formData.append('response', turnstileResponse);

    const verifyUrl = 'https://challenges.cloudflare.com/turnstile/v0/siteverify'
    const verificationResponse = await fetch(verifyUrl, {
        method: 'POST',
        body: formData
    })
    const verificationResult = await verificationResponse.json();

    if (verificationResult.success) {
      res.json({ success: true });
    } else {
      res.json({ success: false });
    }
  } catch (error) {
    console.error('Error during Turnstile verification:', error);
    res.status(500).json({ success: false });
  }
});

app.listen(3000, () => {
  console.log('Server running on http://localhost:3000');
});

4. 运行和测试

启动你的服务器和 Vue 项目,确保一切正常。你现在应该可以在浏览器中访问你的应用程序,看到 Turnstile 验证并进行表单提交。

通过以上步骤,你可以在 Vue 3 项目中集成 Cloudflare Turnstile,增强表单的安全性。确保在实际应用中使用正确的密钥和配置,以最大程度地提高安全性和可靠性。