在网络安全的战场上,验证码作为区分人类用户与机器程序的第一道防线,其重要性不言而喻。然而,传统字符验证码存在用户体验差、机器识别率高等问题,难以平衡安全性与易用性。
今天我们来聊一下 "开源界最好用的行为验证码工具 tianai-captcha"。
基于以上问题,tianai-captcha(简称TAC)应运而生,它是一款基于Java开发的行为验证码系统,通过滑动、旋转、点选等交互方式,在提升安全性的同时显著改善了用户体验。该项目已加入Dromara开源社区,被誉为"开源界最好用的行为验证码工具"。
项目资源
多样化的验证码类型
tianai-captcha支持丰富的行为验证码类型,包括:
滑块验证码:通过轨迹分析识别人类操作特征
旋转验证码:基于角度匹配的防护方案
滑动还原验证码:动态生成算法确保每次挑战唯一
文字点选验证码:语义化交互提升无障碍体验
图标验证码:图形化识别,提升趣味性
语序验证码:要求用户按正确顺序排列词语
刮刮乐验证码:模拟现实刮奖体验
安全性与用户体验的完美平衡
与传统验证码相比,tianai-captcha在多个维度表现出色:
| 特性 | tianai-captcha | 传统验证码 |
|---|---|---|
| 防护强度 | ⭐⭐⭐⭐⭐ | ⭐⭐ |
| 用户完成时间 | 约2.3秒 | 约5.8秒 |
| 移动端适配 | 全自动响应式 | 需手动调整 |
| 用户完成率 | 高达92% | 约85% |
| 恶意请求拦截率 | 98.7% | - |
技术优势
轻量级设计:核心包仅2.3MB,对系统资源消耗极小
高并发支持:分布式缓存支持下,验证数据TPS可达12,000+
快速响应:平均响应时间控制在150-200ms以内
多端兼容:支持PC端、移动端及iOS/Android内嵌Webview
兼容性:Chrome、Firefox、Safari、Opera、主流手机浏览器、iOS 及 Android上的内嵌Webview
框架支持:H5、Angular、React、Vue2、Vue3
1、 将前端sdk的具体js文件下载到项目中、或者放到某个可以访问到地方,比如oss之类的可以被浏览器访问到的地方供加载函数调用 tac下载地址 https://gitee.com/dromara/tianai-captcha/releases/tag/tianai-captcha-1.5.3 (opens new window),里面包含tac.js和tac.css等
2、 引入初始化函数 load.js下载地址 https://minio.tianai.cloud/public/static/captcha/js/load.min.js (opens new window)可自己将load.js下载到本地(右键->另存为)
html<html>
<head>
<!-- 引入验证码初始化js -->
<script src="load.min.js"></script>
</head>
<body>...</body>
</html>
3、创建一个div块用于渲染验证码, 该div用于装载验证码
html <div id="captcha-box"></div>
4、在需要调用验证码的时候执行加载验证码方法
jsfunction login() {
// config 对象为TAC验证码的一些配置和验证的回调
const config = {
// 生成接口 (必选项,必须配置, 要符合tianai-captcha默认验证码生成接口规范)
requestCaptchaDataUrl: "/gen",
// 验证接口 (必选项,必须配置, 要符合tianai-captcha默认验证码校验接口规范)
validCaptchaUrl: "/check",
// 验证码绑定的div块 (必选项,必须配置)
bindEl: "#captcha-box",
// 验证成功回调函数(必选项,必须配置)
validSuccess: (res, c, tac) => {
// 销毁验证码服务
tac.destroyWindow();
console.log("验证成功,后端返回的数据为", res);
// 调用具体的login方法
login(res.data.token)
},
// 验证失败的回调函数(可忽略,如果不自定义 validFail 方法时,会使用默认的)
validFail: (res, c, tac) => {
console.log("验证码验证失败回调...")
// 验证失败后重新拉取验证码
tac.reloadCaptcha();
},
// 刷新按钮回调事件
btnRefreshFun: (el, tac) => {
console.log("刷新按钮触发事件...")
tac.reloadCaptcha();
},
// 关闭按钮回调事件
btnCloseFun: (el, tac) => {
console.log("关闭按钮触发事件...")
tac.destroyWindow();
}
}
// 一些样式配置, 可不传
let style = {
logoUrl: null// 去除logo
// logoUrl: "/xx/xx/xxx.png" // 替换成自定义的logo
}
// 这里分享一些作者自己调的样式供参考
// const style = {
// // 按钮样式
// btnUrl: "https://minio.tianai.cloud/public/captcha-btn/btn3.png",
// // 背景样式
// bgUrl: "https://minio.tianai.cloud/public/captcha-btn/btn3-bg.jpg",
// // logo地址
// logoUrl: "https://minio.tianai.cloud/public/static/captcha/images/logo.png",
// // 滑动边框样式
// moveTrackMaskBgColor: "#f7b645",
// moveTrackMaskBorderColor: "#ef9c0d"
// }
// -------------- 拉起TAC验证码 -----------------
// 参数1: tac文件的URL地址前缀, 目录里包含 tac的js和css等文件,
// 比如参数为: http://xxxx/tac/, 该js会自动加载 http://xxxx/tac/js/tac.min.js 、http://xxxx/tac/css/tac.css等
// 具体的js文件可以在 https://gitee.com/tianai/tianai-captcha-web-sdk/releases/tag/1.2 下载
// 参数2: tac验证码相关配置
// 参数3: tac窗口一些样式配置
window.initTAC("./tac", config, style).then(tac => {
tac.init(); // 调用init则显示验证码
}).catch(e => {
console.log("初始化tac失败", e);
})
}
对于Spring Boot项目,只需简单几步即可完成集成:
xml<dependency>
<groupId>cloud.tianai.captcha</groupId>
<artifactId>tianai-captcha-springboot-starter</artifactId>
<version>1.5.3</version>
</dependency>
在application.yaml中配置验证码相关配置
yaml# 滑块验证码配置, 详细请看 cloud.tianai.captcha.autoconfiguration.ImageCaptchaProperties 类
captcha:
# 如果项目中使用到了redis,滑块验证码会自动把验证码数据存到redis中, 这里配置redis的key的前缀,默认是captcha:slider
prefix: captcha
# 验证码过期时间,默认是2分钟,单位毫秒, 可以根据自身业务进行调整
expire:
# 默认缓存时间 2分钟
default: 10000
# 针对 点选验证码 过期时间设置为 2分钟, 因为点选验证码验证比较慢,把过期时间调整大一些
WORD_IMAGE_CLICK: 20000
# 使用加载系统自带的资源, 默认是 false(这里系统的默认资源包含 滑动验证码模板/旋转验证码模板,如果想使用系统的模板,这里设置为true)
init-default-resource: true
# 缓存控制, 默认为false不开启
local-cache-enabled: false
# 缓存开启后,验证码会提前缓存一些生成好的验证数据, 默认是20
local-cache-size: 20
# 缓存开启后,缓存拉取失败后等待时间 默认是 5秒钟
local-cache-wait-time: 5000
# 缓存开启后,缓存检查间隔 默认是2秒钟
local-cache-period: 2000
# 配置字体包,供文字点选验证码使用,可以配置多个,不配置使用默认的字体
font-path:
- classpath:font/SimHei.ttf
secondary:
# 二次验证, 默认false 不开启
enabled: false
# 二次验证过期时间, 默认 2分钟
expire: 120000
# 二次验证缓存key前缀,默认是 captcha:secondary
keyPrefix: "captcha:secondary"
使用 ImageCaptchaApplication 生成验证码数据对象
java@RestController
public class TestController {
@Autowired
private ImageCaptchaApplication application;
@GetMapping("/genCaptcha")
public void genCaptcha() {
// 1.生成验证码(该数据返回给前端用于展示验证码数据)
// 参数1为具体的验证码类型, 默认支持 SLIDER、ROTATE、WORD_IMAGE_CLICK、CONCAT 等验证码类型,详见: `CaptchaTypeConstant`类
return application.generateCaptcha(CaptchaTypeConstant.SLIDER);
}
}
使用 ImageCaptchaApplication 校验客户端提交的验证码数据
java@RestController
public class TestController {
@Autowired
private ImageCaptchaApplication application;
@PostMapping("/check")
public ApiResponse<?> checkCaptcha(@RequestBody Data data) {
ApiResponse<?> response = imageCaptchaApplication.matching(data.getId(), data.getData());
if (response.isSuccess()) {
// 验证码验证成功,此处应该进行自定义业务处理, 或者返回验证token进行二次验证等。
return ApiResponse.ofSuccess(Collections.singletonMap("validToken", data.getId()));
}
return response;
}
@lombok.Data
public static class Data {
// 验证码id
private String id;
// 验证码数据
private ImageCaptchaTrack data;
// 可以加用户自定义业务参数...
}
}
通过扩展ResourceStore接口添加自定义背景图片
添加模板使用 addTemplate(type1, template1) 方法, type1: 验证码类型, template1: 验证码模板相关数据
添加背景图片使用 addResource(type1, res1)方法, type1: 验证码类型, res1: 验证码背景图片数据
java@Component
@RequiredArgsConstructor
public class CaptchaResourceConfiguration {
private final CrudResourceStore resourceStore;
@PostConstruct
public void init() {
// 滑块验证码 模板 (系统内置) ,这里添加的模板等同于 captcha.init-default-resource=true , 如果配置中设置了加载默认模板,这里模板可不用配置
ResourceMap template1 = new ResourceMap("default", 4);
template1.put("active.png", new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/active.png")));
template1.put("fixed.png", new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/1/fixed.png")));
ResourceMap template2 = new ResourceMap("default", 4);
template2.put("active.png", new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/active.png")));
template2.put("fixed.png", new Resource(ClassPathResourceProvider.NAME, DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/2/fixed.png")));
// 旋转验证码 模板 (系统内置)
ResourceMap template3 = new ResourceMap("default", 4);
template3.put("active.png", new Resource(ClassPathResourceProvider.NAME, StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/3/active.png")));
template3.put("fixed.png", new Resource(ClassPathResourceProvider.NAME, StandardSliderImageCaptchaGenerator.DEFAULT_SLIDER_IMAGE_TEMPLATE_PATH.concat("/3/fixed.png")));
// 1. 添加一些模板
addTemplate(CaptchaTypeConstant.SLIDER, template1);
addTemplate(CaptchaTypeConstant.SLIDER, template2);
addTemplate(CaptchaTypeConstant.ROTATE, template3);
// 2. 添加自定义背景图片, resource 的参数1为资源类型(默认支持 classpath/file/url ), resource 的参数2为资源路径, resource 的参数3为标签
resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bgimages/a.jpg", "default"));
resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bgimages/b.jpg", "default"));
resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bgimages/c.jpg", "default"));
resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bgimages/d.jpg", "default"));
resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bgimages/e.jpg", "default"));
resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bgimages/g.jpg", "default"));
resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bgimages/h.jpg", "default"));
resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bgimages/i.jpg", "default"));
resourceStore.addResource(CaptchaTypeConstant.SLIDER, new Resource("classpath", "bgimages/j.jpg", "default"));
resourceStore.addResource(CaptchaTypeConstant.ROTATE, new Resource("classpath", "bgimages/48.jpg", "default"));
resourceStore.addResource(CaptchaTypeConstant.CONCAT, new Resource("classpath", "bgimages/48.jpg", "default"));
resourceStore.addResource(CaptchaTypeConstant.WORD_IMAGE_CLICK, new Resource("classpath", "bgimages/c.jpg", "default"));
}
}
对于高安全场景,可以开启二次验证,如果设置配置文件 captcha.secondary.enabled=true 时开启了二次验证
java@RestController
public class TestController {
@Autowired
private ImageCaptchaApplication sca;
@RestController
public class TestController {
@Autowired
private ImageCaptchaApplication application;
@PostMapping("/login")
public void genCaptcha(@RequestParam String validToken) {
// 1.生成验证码(该数据返回给前端用于展示验证码数据)
// 参数1为具体的验证码类型, 默认支持 SLIDER、ROTATE、WORD_IMAGE_CLICK、CONCAT 等验证码类型,详见: `CaptchaTypeConstant`类
boolean valid = ((SecondaryVerificationApplication) application).secondaryVerification(id);
if (valid) {
// 验证码验证成功,此处进行自定义业务处理
}
throw new RuntimeException("验证码验证失败");
}
}
}
生产环境建议配置Redis集群存储验证数据,提升并发性能
图片资源建议使用CDN加速加载,提升用户体验
缓存配置根据业务量调整本地缓存大小,默认20个验证码
JDK 1.8+ 环境运行最佳
Spring Boot 2.x 完全兼容
Redis(可选,生产环境推荐)
定期更新背景图资源,建议每周更新,防止图库攻击
开启IP频率限制,建议10次/分钟,防止暴力攻击
禁止前端直接返回校验原始数据,确保数据安全
验证区域不小于300×150px,确保触摸精度
调整触摸事件采样频率,优化移动端体验
使用响应式布局方案,适配不同屏幕尺寸
tianai-captcha 作为一款开源行为验证码工具,成功解决了传统验证码在安全性、用户体验和开发效率之间的平衡问题。通过简单集成,开发者可以快速为系统添加多种炫酷且安全的行为验证码,有效防御机器攻击的同时提升用户满意度。
无论是创业项目还是企业级应用,tianai-captcha 都能提供可靠的验证码解决方案,让开发者专注于核心业务,而不必在验证码模块投入过多开发维护成本。
本文作者:柳始恭
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!