hCaptcha 人机验证集成文档
hCaptcha 人机验证集成文档
📋 项目概述
本项目在登录、注册、忘记密码三个核心页面集成了 hCaptcha 人机验证,防止机器人攻击和恶意注册。
✅ 已实现的功能
1. 登录页面验证
-
✅ hCaptcha 验证码
-
✅ 登录次数限制:失败 5 次后冻结 24 小时
-
✅ 自动解封:24 小时后自动重置失败次数
2. 注册页面验证
-
✅ hCaptcha 验证码
-
✅ 邮箱验证码(6位数字)
-
✅ 发送次数限制:每天最多 5 次
3. 忘记密码验证
-
✅ hCaptcha 验证码
-
✅ 邮箱验证码(6位数字)
-
✅ 发送次数限制:每天最多 5 次
-
✅ 验证码有效期:10 分钟
🔧 技术实现
后端实现
1. 统一验证工具
文件:src/utils/hcaptcha.ts
const hcaptcha = require('hcaptcha');
export async function verify(token: string): Promise<{ success: boolean; message?: string }> {
const secretKey = process.env.HCAPTCHA_SECRET_KEY;
// 未配置密钥时返回错误
if (!secretKey) {
return {
success: false,
message: 'hCaptcha 密钥未配置'
};
}
try {
// 调用 hcaptcha 包的 verify 方法
const result = await hcaptcha.verify(secretKey, token);
return {
success: result.success === true,
message: result.message || result['error-codes']?.join(', ')
};
} catch (error: any) {
return {
success: false,
message: error.message || '验证失败'
};
}
}
2. 登录接口
文件:src/routes/login.ts
关键代码:
app.post('/login', async (request, reply) => {
const { email, password, hcaptcha_token } = request.body;
// 验证 hCaptcha token
if (!hcaptcha_token || hcaptcha_token === 'no-captcha') {
return reply.code(400).send({
code: 400,
message: '请完成验证码'
});
}
const verifyResult = await verifyCaptcha(hcaptcha_token);
if (!verifyResult.success) {
return reply.code(400).send({
code: 400,
message: '验证码验证失败'
});
}
// 继续登录验证...
});
验证逻辑:
-
检查 hCaptcha token 是否存在
-
调用 hCaptcha 验证服务
-
验证登录失败次数(5 次后冻结 24 小时)
-
密码验证
-
登录成功或返回错误
3. 注册接口
文件:src/routes/register.ts
关键代码:
app.post('/register', async (request, reply) => {
const { username, password, email, code, hcaptcha_token } = request.body;
// 验证 hCaptcha
if (!hcaptcha_token || hcaptcha_token === 'no-captcha') {
return reply.code(400).send({
code: 400,
message: '请完成验证码'
});
}
const verifyResult = await verifyCaptcha(hcaptcha_token);
if (!verifyResult.success) {
return reply.code(400).send({
code: 400,
message: '验证码验证失败'
});
}
// 验证邮箱验证码
const db_code = await collection("web_user_code").findOne({ email, code });
// ...
});
发送验证码:
app.post('/register/sendCode', async (request, reply) => {
// 1. 验证邮箱格式
// 2. 检查每天发送次数(最多 5 次)
// 3. 检查邮箱是否已存在
// 4. 生成 6 位验证码
// 5. 发送邮件
// 6. 保存验证码到数据库
});
4. 忘记密码接口
文件:src/routes/login.ts
关键代码:
app.post('/forget/sendCode', async (request, reply) => {
// 1. 验证邮箱格式
// 2. 检查邮箱是否存在
// 3. 检查每天发送次数(最多 5 次)
// 4. 生成 6 位验证码
// 5. 发送邮件
});
app.post('/forget', async (request, reply) => {
// 1. 验证 hCaptcha token
// 2. 验证邮箱验证码
// 3. 检查验证码是否过期(10 分钟)
// 4. 更新密码
// 5. 删除验证码记录
});
前端实现
1. 引入 hCaptcha 脚本
所有页面都需要在 <head> 中添加:
<script src="https://js.hcaptcha.com/1/api.js" async defer></script>
2. 添加验证码组件
在表单中添加:
<!-- hCaptcha 验证码 -->
<div class="flex justify-center py-2">
<div class="h-captcha" data-sitekey="{{hcaptcha_site_key}}"></div>
</div>
3. 表单提交逻辑
在 JavaScript 中:
// 获取 hCaptcha token
const hcaptchaToken = hcaptcha.getResponse();
// 检查验证码是否完成
if (!hcaptchaToken) {
showErrorToast('请完成验证码');
return;
}
// 发送请求,带上 token
fetch('/login', {
method: 'POST',
body: JSON.stringify({
email,
password,
hcaptcha_token: hcaptchaToken
})
});
// 成功后重置验证码
if (typeof hcaptcha !== 'undefined') {
hcaptcha.reset();
}
📁 文件结构
src/
├── routes/
│ ├── login.ts # 登录 + 忘记密码路由
│ └── register.ts # 注册路由
├── utils/
│ └── hcaptcha.ts # hCaptcha 验证工具
views/
├── login.hbs # 登录页面
├── register.hbs # 注册页面
└── forget.hbs # 忘记密码页面
⚙️ 配置说明
环境变量
文件:.env
# hCaptcha 配置
HCAPTCHA_SITE_KEY=your_site_key_here # 前端显示密钥
HCAPTCHA_SECRET_KEY=your_secret_key_here # 后端验证密钥
获取密钥步骤
-
访问 https://www.hcaptcha.com/
-
注册账号并登录
-
创建站点(选择验证码类型)
-
获取密钥:
-
Site Key - 用于前端(公开)
-
Secret Key - 用于后端(保密)
-
本地测试
开发环境如果是 localhost,会显示警告,但不影响使用。
如需移除警告,可在 hCaptcha 后台:
-
添加
localhost或127.0.0.1到允许的域名 -
或使用测试密钥(仅用于开发)
🔐 安全特性
1. 多层验证
-
hCaptcha:防止机器人自动化
-
邮箱验证码:确认邮箱所有权
-
登录限制:防止暴力破解
2. 发送限制
-
邮箱验证码:每天最多 5 次
-
防止恶意刷取验证码
3. 验证码过期
-
邮箱验证码:10 分钟有效
-
提高安全性
4. 账户保护
-
登录失败 5 次:冻结 24 小时
-
防止暴力破解
📦 安装的依赖
pnpm add hcaptcha
🚀 使用流程
登录流程
-
用户输入邮箱密码
-
完成 hCaptcha 验证
-
提交 → 后端验证 token
-
验证登录失败次数
-
密码验证
-
登录成功
注册流程
-
用户填写注册信息
-
输入邮箱,点击"发送验证码"
-
接收邮件,输入验证码
-
完成 hCaptcha 验证
-
提交 → 后端同时验证邮箱验证码和 hCaptcha token
-
注册成功
忘记密码流程
-
输入邮箱,点击"发送验证码"
-
接收邮件,输入验证码
-
输入新密码
-
完成 hCaptcha 验证
-
提交 → 后端验证所有信息
-
更新密码成功
🎯 拓展方案
1. Google reCAPTCHA v3
特点:
-
完全无感,用户体验最好
-
Google 提供,技术成熟
-
免费,无使用限制
集成方式:
// 后端验证
const response = await fetch(`https://www.google.com/recaptcha/api/siteverify?secret=${SECRET_KEY}&response=${token}`);
const data = await response.json();
前端集成:
<script src="https://www.google.com/recaptcha/api.js?render=SITE_KEY"></script>
对比:
-
✅ 用户体验:最好(无感)
-
✅ 免费额度:无限
-
✅ 技术成熟:Google
-
❌ 国内访问:可能较慢
2. Cloudflare Turnstile
特点:
-
免费且无需费用
-
用户体验好(轻量级)
-
技术先进(Cloudflare 提供)
集成方式:
<!-- 前端 -->
<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>
<div class="cf-turnstile" data-sitekey="SITE_KEY"></div>
<!-- 后端 -->
const response = await fetch('https://challenges.cloudflare.com/turnstile/v0/siteverify', {
method: 'POST',
body: JSON.stringify({
secret: SECRET_KEY,
response: token
})
});
对比:
-
✅ 完全免费
-
✅ 体验好
-
✅ 性能优秀
-
✅ 配置简单
3. Microsoft Azure Bot Protection
特点:
-
企业级安全
-
与 Azure AD 集成
-
需要付费计划
适用场景:
-
企业应用
-
需要与 Microsoft 生态系统集成
-
高安全要求
4. 自建图形验证码
实现方式:
-
生成随机图片(如数学题、文字识别)
-
服务端存储答案
-
客户端输入验证
优点:
-
完全自主控制
-
无第三方依赖
-
无费用
缺点:
-
用户体验较差
-
安全性较低(容易被破解)
-
维护成本高
5. 短信验证码
特点:
-
双重验证:邮箱 + 手机
-
安全性高
-
需要 SMS 服务商(如 Twilio、阿里云)
适用场景:
-
金融、支付类应用
-
高安全要求
-
需要手机号认证
6. 多重验证(MFA)
组合方式:
// 1. hCaptcha - 防止机器人
// 2. 邮箱验证码 - 确认邮箱
// 3. 短信验证码 - 双重认证
// 4. TOTP(如 Google Authenticator)- 动态密码
📊 各方案对比
| 方案 | 免费 | 用户体验 | 安全性 | 国内可用 | 推荐度 |
|------|------|---------|--------|---------|--------|
| hCaptcha | ✅ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| reCAPTCHA v3 | ✅ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Turnstile | ✅ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| 自建验证码 | ✅ | ⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| 短信验证码 | ❌ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐ |
| MFA | ✅ | ⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
💡 推荐方案
当前实现
hCaptcha - 已集成,功能完善,适合大多数场景
如果追求更好体验
Cloudflare Turnstile - 免费、无感、性能好
如果需要更高安全
reCAPTCHA v3 + 短信验证 - 多重验证,企业级安全
📝 总结
本项目成功集成了 hCaptcha 人机验证,实现了:
-
✅ 登录、注册、忘记密码三大页面的验证
-
✅ 防止机器人攻击
-
✅ 登录失败次数限制
-
✅ 邮箱验证码机制
-
✅ 完整的错误处理
项目现在具备了完善的验证码保护机制,可以有效防止恶意注册和暴力破解。
本文由萧兮的博客原创发布,欢迎转载,转载务必保留原文链接。
萧兮的博客:https://www.20010515.xyz · 原文:https://www.20010515.xyz/posts/a6cf2841-cb92-4157-a86c-6bff63b784a2