一 产品介绍
腾讯云新一代行为验证码(Captcha),基于十道安全防护策略,为网页、App、小程序开发者打造立体、全面的人机验证。在保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
验证码服务可以帮助您解决以下业务安全问题:
- 登录注册:有效防止撞库攻击、阻止注册机批量注册小号。
- 活动秒杀:有效拦截刷单操作,防止自动机刷取福利券。
- 点赞发帖:有效解决广告屠版、恶意灌水、刷票问题。
- 数据保护:有效防止自动机、爬虫盗取网页内容和数据。
操作简单,部分示例:

二 大致流程

这个流程图可以点击链接看到 验证码 快速入门_腾讯云
大致流程就是:
- 前端请求appid
- 拿到appid后使用腾讯云提供的方法,可以加载出来各种类型的验证码(验证码的类型,看appid申请的是什么样的)
- 用户完成认证后,会得到返回一系列参数,如randstr,ticket
- 前端拿着randstr,ticket请求后端接口,验证这个验证码是否OK,后端返回true或者false
三 腾讯云申请流程
- 在腾讯云官网搜索验证码

-
领取7天免费的,没用过验证码功能的第一次进去会看到领取的地方
-
前往控制台


- 记录下来生成的密钥

5 记录下来自己的账号密钥

四 后端代码编写
1. 总的demo结构

2. pom
XML
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 腾讯云 验证码 -->
<dependency>
<groupId>com.tencentcloudapi</groupId>
<artifactId>tencentcloud-sdk-java</artifactId>
<version>3.1.1297</version>
</dependency>
<!-- Lombok for reducing boilerplate code -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!-- Validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3. Yaml
javascript
server:
port: 8080
spring:
application:
name: tcaptcha-demo
# 日志配置
logging:
level:
org.example: DEBUG
com.tencentcloudapi: INFO
pattern:
console: "%d{yyyy-MM-dd HH:mm:ss} [%thread] %-5level %logger{36} - %msg%n"
# 腾讯云验证码配置
tencent:
captcha:
# 腾讯云API密钥ID
secretId: xxxxxxxxxxxx
# 腾讯云API密钥
secretKey: xxxxxxxxxx
# 验证码应用ID
captchaAppId: 123456789
# 验证码应用密钥
appSecretKey: xxxxxxxx
# API端点
endpoint: xxxxxxxxxxxx
# API服务名称
service: captcha
# API操作名称
action: DescribeCaptchaResult
# 验证码类型
captchaType: 9
# 是否需要获取验证码时间
needGetCaptchaTime: 1
# API版本
version: "2025-07-10"
4. 配置类 config包下
4.1
java
package org.example.config;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* 验证码配置类
*
* @author wangmh
*
*/
@Configuration
@EnableConfigurationProperties(CaptchaProperties.class)
public class CaptchaConfig {
/**
* 配置ObjectMapper
*
* @return ObjectMapper实例
*/
@Bean
public ObjectMapper objectMapper() {
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
return objectMapper;
}
}
java
package org.example.config;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
/**
* 腾讯云验证码配置属性
*
* @author wangmh
*
*/
@Component
@ConfigurationProperties(prefix = "tencent.captcha")
public class CaptchaProperties {
/**
* 腾讯云API密钥ID
*/
private String secretId;
/**
* 腾讯云API密钥
*/
private String secretKey;
/**
* 验证码应用ID
*/
private Integer captchaAppId;
/**
* 验证码类型
*/
private Integer captchaType;
/**
* 是否需要获取验证码时间
*/
private Integer needGetCaptchaTime;
/**
* 应用密钥
*/
private String appSecretKey;
/**
* API版本
*/
private String version;
/**
* API端点
*/
private String endpoint;
/**
* API服务名称
*/
private String service;
/**
* API操作名称
*/
private String action;
// Getters and Setters
public String getSecretId() {
return secretId;
}
public void setSecretId(String secretId) {
this.secretId = secretId;
}
public String getSecretKey() {
return secretKey;
}
public void setSecretKey(String secretKey) {
this.secretKey = secretKey;
}
public Integer getCaptchaAppId() {
return captchaAppId;
}
public void setCaptchaAppId(Integer captchaAppId) {
this.captchaAppId = captchaAppId;
}
public Integer getCaptchaType() {
return captchaType;
}
public void setCaptchaType(Integer captchaType) {
this.captchaType = captchaType;
}
public Integer getNeedGetCaptchaTime() {
return needGetCaptchaTime;
}
public void setNeedGetCaptchaTime(Integer needGetCaptchaTime) {
this.needGetCaptchaTime = needGetCaptchaTime;
}
public String getAppSecretKey() {
return appSecretKey;
}
public void setAppSecretKey(String appSecretKey) {
this.appSecretKey = appSecretKey;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public String getEndpoint() {
return endpoint;
}
public void setEndpoint(String endpoint) {
this.endpoint = endpoint;
}
public String getService() {
return service;
}
public void setService(String service) {
this.service = service;
}
public String getAction() {
return action;
}
public void setAction(String action) {
this.action = action;
}
}
5 实体类 dto包下
java
package org.example.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
/**
* 验证码验证请求DTO
*
* @author wangmh
*
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CaptchaVerifyRequest {
/**
* 用户IP地址
*/
@NotBlank(message = "用户IP地址不能为空")
@JsonProperty("userIp")
private String userIp;
/**
* 随机字符串
*/
@NotBlank(message = "随机字符串不能为空")
@JsonProperty("randstr")
private String randstr;
/**
* 验证票据
*/
@NotBlank(message = "验证票据不能为空")
@JsonProperty("ticket")
private String ticket;
}
java
package org.example.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Data;
import lombok.Builder;
import lombok.NoArgsConstructor;
import lombok.AllArgsConstructor;
/**
* 验证码验证响应DTO
*
* @author wangmh
*
*/
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class CaptchaVerifyResponse {
/**
* 请求ID
*/
@JsonProperty("RequestId")
private String RequestId;
/**
* 验证码验证结果
* 1: 验证通过
*/
@JsonProperty("CaptchaCode")
private Integer CaptchaCode;
/**
* 验证码验证消息
*/
@JsonProperty("CaptchaMsg")
private String CaptchaMsg;
/**
* 前端获取验证码时间
*/
@JsonProperty("GetCaptchaTime")
private Integer GetCaptchaTime;
/**
* 提交验证码时间
*/
@JsonProperty("SubmitCaptchaTime")
private Integer SubmitCaptchaTime;
/**
* 无感验证模式下,该参数返回验证结果
*/
@JsonProperty("EvilLevel")
private Integer EvilLevel;
/**
* 拦截类型
*/
@JsonProperty("EvilBitmap")
private Integer EvilBitmap;
/**
* 是否验证通过
*/
public boolean isSuccess() {
return CaptchaCode != null && CaptchaCode == 1;
}
}
6 Service
java
package org.example.service;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.tencentcloudapi.common.CommonClient;
import com.tencentcloudapi.common.Credential;
import com.tencentcloudapi.common.exception.TencentCloudSDKException;
import com.tencentcloudapi.common.profile.ClientProfile;
import com.tencentcloudapi.common.profile.HttpProfile;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.config.CaptchaProperties;
import org.example.dto.CaptchaVerifyRequest;
import org.example.dto.CaptchaVerifyResponse;
import org.springframework.stereotype.Service;
import jakarta.annotation.PostConstruct;
import org.springframework.util.ObjectUtils;
import java.util.HashMap;
import java.util.Map;
/**
* 腾讯云验证码服务
*
* @author wangmh
*
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class CaptchaService {
private final CaptchaProperties captchaProperties;
private final ObjectMapper objectMapper;
private CommonClient commonClient;
/**
* 初始化腾讯云客户端
*/
@PostConstruct
public void init() {
try {
Credential credential = new Credential(
captchaProperties.getSecretId(),
captchaProperties.getSecretKey()
);
HttpProfile httpProfile = new HttpProfile();
httpProfile.setEndpoint(captchaProperties.getEndpoint());
ClientProfile clientProfile = new ClientProfile();
clientProfile.setHttpProfile(httpProfile);
this.commonClient = new CommonClient(
captchaProperties.getService(),
captchaProperties.getVersion(),
credential,
"",
clientProfile
);
log.info("腾讯云验证码客户端初始化成功");
} catch (Exception e) {
log.error("腾讯云验证码客户端初始化失败", e);
throw new RuntimeException("腾讯云验证码客户端初始化失败", e);
}
}
/**
* 验证验证码
*
* @param request 验证请求
* @return 验证响应
*/
public CaptchaVerifyResponse verifyCaptcha(CaptchaVerifyRequest request) throws TencentCloudSDKException {
try {
Map<String, Object> params = buildRequestParams(request);
String paramsJson = objectMapper.writeValueAsString(params);
log.info("验证码请求参数: {}", paramsJson);
String response = commonClient.call(captchaProperties.getAction(), paramsJson);
log.info("腾讯云API响应: {}", response);
Map<String, Object> responseMap = objectMapper.readValue(response, Map.class);
CaptchaVerifyResponse captchaResponse = buildCaptchaResponse(responseMap);
return captchaResponse;
} catch (TencentCloudSDKException e) {
log.error("腾讯云API调用失败", e);
throw e;
} catch (Exception e) {
log.error("验证码验证过程中发生异常", e);
throw new RuntimeException("验证码验证失败", e);
}
}
/**
* 构建请求参数
*
* @param request 验证请求
* @return 请求参数Map
*/
private Map<String, Object> buildRequestParams(CaptchaVerifyRequest request) {
Map<String, Object> params = new HashMap<>();
// 从配置中获取的参数
params.put("CaptchaAppId", captchaProperties.getCaptchaAppId());
params.put("CaptchaType", captchaProperties.getCaptchaType());
params.put("NeedGetCaptchaTime", captchaProperties.getNeedGetCaptchaTime());
params.put("AppSecretKey", captchaProperties.getAppSecretKey());
// 从请求中获取的参数
params.put("UserIp", request.getUserIp());
params.put("Randstr", request.getRandstr());
params.put("Ticket", request.getTicket());
return params;
}
/**
* 简单验证方法 - 只返回是否验证通过
*
* @param userIp 用户IP
* @param randstr 随机字符串
* @param ticket 验证票据
* @return 是否验证通过
*/
public boolean isCaptchaValid(String userIp, String randstr, String ticket) {
try {
CaptchaVerifyRequest request = CaptchaVerifyRequest.builder()
.userIp(userIp)
.randstr(randstr)
.ticket(ticket)
.build();
CaptchaVerifyResponse response = verifyCaptcha(request);
return response.isSuccess();
} catch (Exception e) {
log.error("验证码验证失败", e);
return false;
}
}
/**
* 构建验证码响应对象
*
* @param responseMap 响应Map
* @return 验证码响应对象
*/
private CaptchaVerifyResponse buildCaptchaResponse(Map<String, Object> responseMap) {
CaptchaVerifyResponse response = new CaptchaVerifyResponse();
try {
if (responseMap.containsKey("Response")) {
Map<String, Object> responseData = (Map<String, Object>) responseMap.get("Response");
populateResponse(response, responseData);
}
} catch (Exception e) {
log.error("解析响应数据失败", e);
}
return response;
}
/**
* 填充响应数据
*
* @param response 响应对象
* @param data 数据Map
*/
private void populateResponse(CaptchaVerifyResponse response, Map<String, Object> data) {
if (data.containsKey("RequestId")) {
response.setRequestId((String) data.get("RequestId"));
}
if (data.containsKey("CaptchaCode")) {
Object v = data.get("CaptchaCode");
if (!ObjectUtils.isEmpty(v))
response.setCaptchaCode(v instanceof Integer ? (Integer) v : Integer.parseInt(v.toString()));
}
if (data.containsKey("CaptchaMsg")) {
response.setCaptchaMsg((String) data.get("CaptchaMsg"));
}
if (data.containsKey("GetCaptchaTime")) {
Object v = data.get("GetCaptchaTime");
if (!ObjectUtils.isEmpty(v))
response.setGetCaptchaTime(v instanceof Integer ? (Integer) v : Integer.parseInt(v.toString()));
}
if (data.containsKey("SubmitCaptchaTime")) {
Object v = data.get("SubmitCaptchaTime");
if (!ObjectUtils.isEmpty(v))
response.setSubmitCaptchaTime(v instanceof Integer ? (Integer) v : Integer.parseInt(v.toString()));
}
if (data.containsKey("EvilLevel")) {
Object v = data.get("EvilLevel");
if (!ObjectUtils.isEmpty(v))
response.setEvilLevel(v instanceof Integer ? (Integer) v : Integer.parseInt(v.toString()));
}
if (data.containsKey("EvilBitmap")) {
Object v = data.get("EvilBitmap");
if (!ObjectUtils.isEmpty(v))
response.setEvilBitmap(v instanceof Integer ? (Integer) v : Integer.parseInt(v.toString()));
}
}
}
6. Controller
java
package org.example.controller;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.example.config.CaptchaProperties;
import org.example.dto.CaptchaVerifyRequest;
import org.example.dto.CaptchaVerifyResponse;
import org.example.service.CaptchaService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import jakarta.validation.Valid;
/**
* 验证码控制器
*
* @author wangmh
*
*/
@Slf4j
@RestController
@RequestMapping("/api/captcha")
@RequiredArgsConstructor
public class CaptchaController {
private final CaptchaService captchaService;
private final CaptchaProperties captchaProperties;
/**
* 验证验证码
*
* @param request 验证请求
* @return 验证结果
*/
@PostMapping("/verify")
public ResponseEntity<CaptchaVerifyResponse> verifyCaptcha(@Valid @RequestBody CaptchaVerifyRequest request) {
try {
log.info("收到简单验证码验证请求: userIp={}, randstr={}", request.getUserIp(), request.getRandstr());
CaptchaVerifyResponse response = captchaService.verifyCaptcha(request);
return ResponseEntity.ok(response);
} catch (Exception e) {
log.error("验证码验证失败", e);
return ResponseEntity.internalServerError().build();
}
}
/**
* 简单验证接口
*
* @param userIp 用户IP
* @param randstr 随机字符串
* @param ticket 验证票据
* @return 是否验证通过
*/
@GetMapping("/verify")
public ResponseEntity<Boolean> verifyCaptchaSimple(
@RequestParam String userIp,
@RequestParam String randstr,
@RequestParam String ticket) {
try {
log.info("收到简单验证码验证请求: userIp={}, randstr={}", userIp, randstr);
boolean isValid = captchaService.isCaptchaValid(userIp, randstr, ticket);
log.info("收到简单验证码验证请求: userIp={}, randstr={} 验证结果:{}", userIp, randstr, isValid);
return ResponseEntity.ok(isValid);
} catch (Exception e) {
log.error("验证码验证失败", e);
return ResponseEntity.internalServerError().build();
}
}
/**
* 获取验证码应用ID
* @return captchaAppId
*/
@GetMapping("/appid")
public ResponseEntity<Integer> getCaptchaAppId() {
return ResponseEntity.ok(captchaProperties.getCaptchaAppId());
}
}
7. 请求测试

五 前端代码
里面的js 下载地址:https://turing.captcha.qcloud.com/TJCaptcha.js
css 可以删掉
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Web 前端接入示例</title>
<link rel="stylesheet" href="./css/style.css">
<!-- 验证码程序依赖(必须)。请勿修改以下程序依赖,如通过其他手段规避加载,会导致验证码无法正常更新,对抗能力无法保证,甚至引起误拦截。 -->
<script src="./js/TJCaptcha.js"></script>
</head>
<body>
<button id="CaptchaId" type="button">验证</button>
</body>
<script>
// 定义回调函数
function callback(res) {
// 第一个参数传入回调结果,结果如下:
// ret Int 验证结果,0:验证成功。2:用户主动关闭验证码。
// ticket String 验证成功的票据,当且仅当 ret = 0 时 ticket 有值。
// CaptchaAppId String 验证码应用ID。
// bizState Any 自定义透传参数。
// randstr String 本次验证的随机串,后续票据校验时需传递该参数。
// verifyDuration Int 验证码校验接口耗时(ms)。
// actionDuration Int 操作校验成功耗时(用户动作+校验完成)(ms)。
// sid String 链路sid。
console.log('callback:', res);
// res(用户主动关闭验证码)= {ret: 2, ticket: null}
// res(验证成功) = {ret: 0, ticket: "String", randstr: "String"}
// res(请求验证码发生错误,验证码自动返回trerror_前缀的容灾票据) = {ret: 0, ticket: "String", randstr: "String", errorCode: Number, errorMessage: "String"}
// 此处代码仅为验证结果的展示示例,真实业务接入,建议基于ticket和errorCode情况做不同的业务处理
if (res.ret === 0) {
// 复制结果至剪切板
var str = '【randstr】->【' + res.randstr + '】 【ticket】->【' + res.ticket + '】';
var ipt = document.createElement('input');
ipt.value = str;
document.body.appendChild(ipt);
ipt.select();
document.execCommand("Copy");
document.body.removeChild(ipt);
alert('1. 返回结果(randstr、ticket)已复制到剪切板,ctrl+v 查看。2. 打开浏览器控制台,查看完整返回结果。');
}
}
// 定义验证码js加载错误处理函数
function loadErrorCallback() {
var appid = '您的CaptchaAppId';
// 生成容灾票据或自行做其它处理
var ticket = 'trerror_1001_' + appid + '_' + Math.floor(new Date().getTime() / 1000);
callback({
ret: 0,
randstr: '@' + Math.random().toString(36).substr(2),
ticket: ticket,
errorCode: 1001,
errorMessage: 'jsload_error'
});
}
// 定义验证码触发事件
window.onload = function () {
document.getElementById('CaptchaId').onclick = function () {
try {
// 生成一个验证码对象
// CaptchaAppId:登录验证码控制台,从【验证管理】页面进行查看。如果未创建过验证,请先新建验证。注意:不可使用客户端类型为小程序的CaptchaAppId,会导致数据统计错误。
//callback:定义的回调函数
var captcha = new TencentCaptcha('198595300', callback, {
userLanguage: 'zh-cn',
showFn: (ret) => {
const {
duration, // 验证码渲染完成的耗时(ms)
sid, // 链路sid
} = ret;
},
});
// 调用方法,显示验证码
captcha.show();
} catch (error) {
// 加载异常,调用验证码js加载错误处理函数
loadErrorCallback();
}
}
}
</script>
</html>
六 官方文档
验证码产品页面:T-sec-腾讯安全天御-行为式验证码 Captcha-腾讯云
产品叙述:验证码 产品概述_腾讯云
web端接入:验证码 Web 客户端接入_腾讯云
接收票据校验:验证码 接入票据校验(Web 及 App)_腾讯云
核验验证码票据结果:验证码 核查验证码票据结果(Web及APP)_腾讯云
jar包引入:云产品SDK中心_云产品SDK文档-腾讯云