Cloudflare Turnstile 在 Java 后端的人机验证实践
现代 Web 应用中,表单接口常是恶意机器人的目标。相比 Google reCAPTCHA,Cloudflare Turnstile 更轻量、隐私友好且完全免费。下面分享一个完整的前后端接入流程。
一、Cloudflare 控制台配置
登录 Cloudflare Dashboard,进入 Turnstile 页面点击'Add site'。
- Site name:自定义,如 My Demo
- Domain:本地测试可选 Non-website
- Widget type:推荐 Managed
创建后获取两段密钥:Site key(前端用)和 Secret key(后端用)。切记 secret key 绝不可暴露在前端代码中。
二、前端嵌入组件
在 HTML 中引入脚本并放置验证容器。
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>Cloudflare Turnstile 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. 依赖准备
确保项目包含 Web 和 Jackson 依赖。
<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. 控制器逻辑
这里使用 JDK 自带的 HttpClient 发起请求,避免额外依赖。
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。
Linux/Mac:
export TURNSTILE_SECRET="你的_secret_key"
mvn spring-boot:run
Windows:
set TURNSTILE_SECRET=你的_secret_key
mvn spring-boot:run
访问 http://localhost:8080/ 填写表单并提交。若验证通过,将看到成功提示。
五、安全最佳实践
- 密钥管理:Secret Key 必须放在环境变量或密钥管理系统中,严禁硬编码。
- Token 时效:Turnstile Token 有效期仅 5 分钟,且只能使用一次。
- HTTPS:生产环境务必启用 HTTPS,防止中间人攻击窃取 Token。
- 日志记录:对验证失败的错误码(如
invalid-input-secret)进行记录以便排查。
六、总结
Cloudflare Turnstile 无需用户手动点选,体验流畅且保护隐私。对于 Java 开发者而言,结合 Spring Boot 快速集成,既能提升表单安全性,又不会牺牲用户体验。
参考文档:
