使用 Cloudflare Turnstile 实现 Java 后端的人机验证
时间:2025 年
标签:Java、Spring Boot、Cloudflare、验证码、人机验证
💡 背景
在现代 Web 应用中,表单接口经常成为恶意机器人的攻击目标。
传统的 Google reCAPTCHA 尽管流行,但存在隐私与加载延迟问题。
Cloudflare Turnstile 是 Cloudflare 推出的新一代无痕人机验证(CAPTCHA 替代方案),它轻量、隐私友好、加载快,并且完全免费。
本文将带你一步步实现一个:
✅ 前端嵌入 Cloudflare Turnstile
✅ Java 后端验证 token 的完整流程。
最终效果如下:
用户打开表单 → 完成人机验证 → 后端验证通过 → 返回业务结果。
🧭 一、在 Cloudflare 控制台创建 Turnstile
-
登录 Cloudflare:
👉 https://dash.cloudflare.com -
左侧菜单中选择 Turnstile(或访问)
https://dash.cloudflare.com/?to=/:account/turnstile -
点击 “Add site”,填写:
- Site name:任意,例如「My Java Demo」
- Domain:可以选择 “Non-website”(用于本地测试)
- Widget type:选择 “Managed”(推荐)
-
创建成功后,Cloudflare 会生成两段密钥:
- Site key:用于前端页面加载组件
- Secret key:用于后端验证 token
⚠️ 注意:
secret key 只能用于服务器端,切勿暴露在前端或版本库中。
🧩 二、前端页面(HTML)
前端只需要引入 Cloudflare 的脚本并嵌入验证组件。
文件:src/main/resources/static/index.html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>Cloudflare Turnstile + Java Demo</title>
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
</head>
<body style="font-family:sans-serif;margin:50px;">
<h2>Cloudflare Turnstile + Java 后端验证</h2>
<form action="/verify" method="post">
<label>姓名:</label>
<input type="text" name="name" required /><br><br>
<!-- Turnstile 验证组件 -->
<div class="cf-turnstile"
data-sitekey="替换为你的_SITE_KEY"
data-theme="light">
</div>
<br>
<button type="submit">提交</button>
</form>
</body>
</html>
当用户完成验证后,Turnstile 会自动在表单中生成一个隐藏字段:
cf-turnstile-response
它就是我们需要传给后端验证的 token。
💻 三、后端实现(Spring Boot)
1. 依赖配置(pom.xml)
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
</dependencies>
2. 控制器逻辑(TurnstileController.java)
package com.example.demo;
import org.springframework.web.bind.annotation.*;
import org.springframework.stereotype.Controller;
import java.net.URI;
import java.net.URLEncoder;
import java.net.http.*;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.Map;
import com.fasterxml.jackson.databind.ObjectMapper;
@Controller
public class TurnstileController {
private static final String VERIFY_URL = "https://challenges.cloudflare.com/turnstile/v0/siteverify";
private final HttpClient httpClient = HttpClient.newHttpClient();
private final ObjectMapper json = new ObjectMapper();
@PostMapping("/verify")
@ResponseBody
public String verifyForm(@RequestParam String name,
@RequestParam("cf-turnstile-response") String token,
@RequestHeader(value = "X-Forwarded-For", required = false) String ip) throws Exception {
// 从环境变量读取 secret(推荐方式)
String secret = System.getenv("TURNSTILE_SECRET");
if (secret == null || secret.isEmpty()) {
return "❌ 未配置环境变量 TURNSTILE_SECRET";
}
// 构造表单参数
String body = "secret=" + URLEncoder.encode(secret, StandardCharsets.UTF_8)
+ "&response=" + URLEncoder.encode(token, StandardCharsets.UTF_8);
if (ip != null) {
body += "&remoteip=" + URLEncoder.encode(ip, StandardCharsets.UTF_8);
}
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create(VERIFY_URL))
.timeout(Duration.ofSeconds(10))
.header("Content-Type", "application/x-www-form-urlencoded")
.POST(HttpRequest.BodyPublishers.ofString(body))
.build();
HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
Map<String, Object> result = json.readValue(response.body(), Map.class);
boolean success = Boolean.TRUE.equals(result.get("success"));
if (success) {
return "✅ 验证成功!你好," + name + "。";
} else {
return "❌ 验证失败:" + result;
}
}
}
⚙️ 四、运行与测试
-
设置环境变量(替换为你的
secret key):export TURNSTILE_SECRET="你的_secret_key"Windows:
set TURNSTILE_SECRET=你的_secret_key -
启动项目:
mvn spring-boot:run -
访问:
http://localhost:8080/ -
填写表单、完成人机验证,点击提交。
如果验证成功,你将看到类似:✅ 验证成功!你好,张三。
🔍 五、验证逻辑解析
后端调用的接口是:
POST https://challenges.cloudflare.com/turnstile/v0/siteverify
请求参数:
| 参数名 | 说明 |
|---|---|
secret | 你的服务器端密钥 |
response | 前端表单中的 cf-turnstile-response |
remoteip | (可选)用户的真实 IP |
返回示例:
{
"success": true,
"challenge_ts": "2025-10-16T10:01:32Z",
"hostname": "localhost",
"action": "login"
}
🔒 六、安全与最佳实践
| 建议项 | 说明 |
|---|---|
| Secret 管理 | 放环境变量或密钥管理系统,绝对不要写入代码或前端 |
| Token 有效期 | Turnstile token 有效期 5 分钟,仅能使用一次 |
| IP 校验 | 使用 CF-Connecting-IP 或 X-Forwarded-For 获取真实 IP |
| 错误码 | 对 timeout-or-duplicate、invalid-input-secret 等进行日志记录 |
| HTTPS | 确保生产环境走 HTTPS,防止中间人攻击 |
🌈 七、总结
Cloudflare Turnstile 的最大优点是:
- 免费、轻量、隐私友好;
- 无需用户手动点选验证码;
- 接入简单,只需前端 + 一次 HTTP 验证。
相比 Google reCAPTCHA:
- 不依赖第三方追踪;
- 不要求 Google 账号;
- 验证更流畅、延迟更低。
对于希望提高表单安全性、又不想牺牲用户体验的 Java 开发者来说,Turnstile 是一个非常理想的选择。
594





