使用 Cloudflare Turnstile 实现 Java 后端的人机验证
使用 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")@ResponseBodypublic 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 是一个非常理想的选择。
🧰 参考文档
- Cloudflare 官方 Turnstile 文档
- Turnstile siteverify API
- Spring Boot 官方文档