有奖捉虫:办公协同&微信生态&物联网文档专题 HOT
注意:
为提高验证码产品性能及稳定性,自2023年07月18日起,启用新验证码 JS 地址:https://turing.captcha.qcloud.com/TCaptcha.js 原有验证码 JS 地址:
https://ssl.captcha.qq.com/TCaptcha.js
https://t.captcha.qq.com/TCaptcha.js
https://t.captcha.qcloud.com/TCaptcha.js
https://captcha.gtimg.com/TCaptcha.js
https://captcha.myqcloud.com/TCaptcha.js
https://captcha.cloudcachetci.com/TCaptcha.js
已于2023年08月21日停止使用,请您务必在2023年08月21日前,切换到新验证码 JS 地址,详情请参见 验证码 JS 地址变更指引

前提条件

客户端接入前,需完成新建验证,并在验证列表获取所需的 CaptchaAppId 以及 AppSecretKey。步骤如下:
1. 登录 验证码控制台,左侧导航栏选择图形验证 > 验证管理,进入验证管理页面。
2. 单击新建验证,根据业务场景需求,设置验证名称、客户端类型、验证方式等参数。
3. 单击确定,完成新建验证,即可在验证列表中查看验证码 CaptchaAppId 及 AppSecretKey。

代码示例

以下代码示例,单击验证,激活验证码,并弹窗展示验证结果。
注意
该示例未展示调用票据校验 API 的逻辑。业务客户端完成验证码接入后,业务服务端需二次核查验证码票据结果(未接入票据校验,会导致黑产轻易伪造验证结果,失去验证码人机对抗效果),详情请参见:接入票据校验(Web 及 App)
<!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>
<!-- 验证码程序依赖(必须)。请勿修改以下程序依赖,如通过其他手段规避加载,会导致验证码无法正常更新,对抗能力无法保证,甚至引起误拦截。 -->
<script src="https://turing.captcha.qcloud.com/TCaptcha.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 本次验证的随机串,后续票据校验时需传递该参数。
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('您的验证码CaptchaAppId', callback, {});
// 调用方法,显示验证码
captcha.show();
} catch (error) {
// 加载异常,调用验证码js加载错误处理函数
loadErrorCallback();
}
}
}
</script>

</html>

接入说明

步骤1:动态引入验证码 JS

Web 页面需动态引入验证码 JS,在业务需要验证时,唤起验证码进行验证。
<!-- 动态引入验证码JS示例 -->
<script src="https://turing.captcha.qcloud.com/TCaptcha.js"></script>
注意
必须动态引入验证码 JS。如通过其他手段规避动态加载,会导致验证码无法正常更新,对抗能力无法保证,甚至引起误拦截。

步骤2:创建验证码对象

引入验证码 JS 后,验证码会在全局注册一个TencentCaptcha类,业务方可以使用这个类自行初始化验证码,并对验证码进行显示或者隐藏。
注意
触发验证码的元素不要使用id="TencentCaptcha",TencentCaptcha 属于系统默认 id,用来兼容验证码旧接入方式。

构造函数

new TencentCaptcha(CaptchaAppId, callback, options);
参数说明
参数名
值类型
说明
CaptchaAppId
String
验证码 CaptchaAppId:登录 验证码控制台,在验证管理页面进行查看。如果未创建过验证,请先新建验证。
注意:不可使用客户端类型为小程序的 CaptchaAppId,会导致数据统计错误。
callback
Function
验证码回调函数,详情请参见 callback 回调函数
options
Object
验证码外观配置参数, 详情请参见 options 外观配置参数

callback 回调函数

验证结束后,会调用业务传入的回调函数,并在第一个参数中传入回调结果。回调结果字段说明如下:
字段名
值类型
说明
ret
Int
验证结果,0:验证成功。2:用户主动关闭验证码。
ticket
String
验证成功的票据,当且仅当 ret = 0 时 ticket 有值。
appid
String
验证码应用 ID。
bizState
Any
自定义透传参数。
randstr
String
本次验证的随机串,后续票据校验时需传递该参数。
errorCode
Number
错误 code ,详情请参见 回调函数 errorCode 说明
errorMessage
String
错误信息。

回调函数errorCode说明

errorCode
说明
1001
TCaptcha.js 加载错误
1002
调用 show 方法超时
1003
中间 js 加载超时
1004
中间 js 加载错误
1005
中间 js 运行错误
1006
拉取验证码配置错误/超时
1007
iframe 加载超时
1008
iframe 加载错误
1009
jquery 加载错误
1010
滑块 js 加载错误
1011
滑块 js 运行错误
1012
刷新连续错误3次
1013
验证网络连续错误3次

options 外观配置参数

options 参数用于对验证码进行定制外观设置,默认可以设置为空。
注意
验证码弹窗内部不支持调整样式大小,如果需要调整,可在弹窗最外层用 class=tcaptcha-transform 的元素设置 transform:scale();(更改大小可能会导致验证码图片失真,请谨慎修改)。举例如下:
.tcaptcha-transform{ transform: scale(0.9); }
验证码服务更新可能会改变元素的 id、class 等属性,请勿依赖其他验证码元素属性值覆盖样式。
如果手机原生端有设置左右滑动手势,需在调用验证码 show 方法前禁用,验证完成后再打开,防止与验证码滑动事件冲突。
配置名
值类型
说明
bizState
Any
自定义透传参数,业务可用该字段传递少量数据,该字段的内容会被带入 callback 回调的对象中。
enableDarkMode
Boolean|String
开启自适应深夜模式或强制深夜模式。(VTT 空间语义验证暂不支持该功能
1. 开启自适应深夜模式: {"enableDarkMode": true}
2. 强制深夜模式: {"enableDarkMode": 'force'}
sdkOpts
Object
示例 {"width": 140, "height": 140}
仅支持移动端原生 webview 调用时传入,用来设置验证码 loading 加载弹窗的大小(注意,并非验证码弹窗大小)。
ready
Function
验证码加载完成的回调,回调参数为验证码实际的宽高(单位:px):
{"sdkView": {
"width": number,
"height": number
}}
该参数仅为查看验证码宽高使用,请勿使用此参数直接设定宽高
needFeedBack
Boolean|String
隐藏帮助按钮或自定义帮助按钮链接。(VTT 空间语义验证暂不支持自定义链接
隐藏帮助按钮: {"needFeedBack": false }
自定义帮助链接: {"needFeedBack": 'url地址' }
loading
Boolean
是否在验证码加载过程中显示loading框。不指定该参数时,默认显示loading框。
显示 loading 框: {"loading": true}
不显示 loading 框: {"loading": false} (展示方式为嵌入式时不支持配置)
userLanguage
String
指定验证码提示文案的语言,优先级高于控制台配置。(VTT 空间语义、文字点选验证暂不支持语言配置
支持传入值同 navigator.language 用户首选语言,大小写不敏感。
type
String
定义验证码展示方式。
popup(默认)弹出式,以浮层形式居中弹出展示验证码。
embed 嵌入式,以嵌入指定容器元素中的方式展示验证码。
aidEncrypted
String
CaptchaAppId 加密校验串,可选参数。详情见 CaptchaAppid 加密校验能力接入指引

userLanguage 配置参数

参数名
说明
zh-cn
简体中文
zh-hk
繁体中文(中国香港)
zh-tw
繁体中文(中国台湾)
en
英文
ar
阿拉伯语
my
缅甸语
fr
法语
de
德语
he
希伯来语
hi
印地语
id
印尼语
it
意大利语
ja
日语
ko
朝鲜语/韩语
lo
老挝语
ms
马来语
pl
波兰语
pt
葡萄牙语
ru
俄语
es
西班牙语
th
泰语
tr
土耳其语
vi
越南语
fil
菲律宾语
ur
乌尔都语

步骤3:调用验证码实例方法

TencentCaptcha 的实例提供一些操作验证码的常用方法:
方法名
说明
传入参数
返回内容
show
显示验证码,可以反复调用。
destroy
隐藏验证码,可以反复调用。
getTicket
获取验证成功后的 ticket。
Object:{"CaptchaAppId":"","ticket":""}

步骤4:容灾处理

为保障验证码 Captacha 服务端异常时不阻塞客户网站正常业务流程,建议参考如下方式接入验证码。
1. 定义错误处理函数。
// 错误处理函数作用:在脚本加载或初始化错误时,保障事件流程正常
// 函数定义需在script加载前
function loadErrorCallback() {
var appid = ''
// 生成容灾票据或自行做其它处理
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',
});
}
2. 验证码返回错误时,调用错误处理函数。
try {
// 生成一个验证码对象
var captcha = new TencentCaptcha('您的验证码CaptchaAppId', callback, {});
// 调用方法,显示验证码
captcha.show();
} catch (error) {
// 加载异常,调用验证码js加载错误处理函数
loadErrorCallback();
}
3. 回调函数根据 ticket 和 errorCode (而非 ret)的情况做处理。
function 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"}
if (res.ticket){
//根据errorCode情况做特殊处理
if(res.errorCode === xxxxx){
//自定义容灾逻辑(例如跳过这次验证)
}
}
}
完整容灾方案,详情请见业务容灾方案
注意
业务客户端完成验证码接入后,服务端需二次核查验证码票据结果(未接入票据校验,会导致黑产轻易伪造验证结果,失去验证码人机对抗效果),详情请参见:接入票据校验(Web 及 App)

React 架构接入示例

1. 在 Html 模板文件中引入验证码 JS。
<!-- 验证码程序依赖(必须)。请勿修改以下程序依赖,如使用本地缓存,或通过其他手段规避加载,会导致验证码无法正常更新,对抗能力无法保证,甚至引起误拦截。 -->
<script src="https://turing.captcha.qcloud.com/TCaptcha.js"></script>
2. 调用验证码。

import React from 'react';

import logo from './logo.svg';

import './App.css';

interface ICaptchaResult {
ret: number;

ticket: string;

randstr: string;

CaptchaAppId?: string;

bizState?: string;

errorCode?: number;

errorMessage?: string;
}

function App() {
// 定义回调函数

function callback(res: ICaptchaResult) {
// 第一个参数传入回调结果,结果如下:

// ret Int 验证结果,0:验证成功。2:用户主动关闭验证码。

// ticket String 验证成功的票据,当且仅当 ret = 0 时 ticket 有值。

// CaptchaAppId String 验证码应用ID。

// bizState Any 自定义透传参数。

// randstr String 本次验证的随机串,后续票据校验时需传递该参数。

console.log('callback:', res);

// res(用户主动关闭验证码)= {ret: 2, ticket: null}

// res(验证成功) = {ret: 0, ticket: "String", randstr: "String"}

// res(请求验证码发生错误,验证码自动返回terror_前缀的容灾票据) = {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 = 'terror_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',
});
}

function onCaptchaShow() {
try {
// 生成一个验证码对象

// CaptchaAppId:登录验证码控制台,从【验证管理】页面进行查看。如果未创建过验证,请先新建验证。注意:不可使用客户端类型为小程序的CaptchaAppId,会导致数据统计错误。

// callback:定义的回调函数

const captcha = new TencentCaptcha('您的CaptchaAppId', callback, {});

// 调用方法,显示验证码

captcha.show();
} catch (error) {
// 加载异常,调用验证码js加载错误处理函数

loadErrorCallback();
}
}

return (
<div className='App'>
<button className='captcha-btn' onClick={onCaptchaShow}>
弹出验证码
</button>
</div>
);
}

export default App;




CaptchaAppid 加密校验能力接入指引

通过前端传递加密符(非必选能力,可根据安全性需求选择性接入),可以有效防止因 CaptchaAppid 泄露而造成的资源盗刷。

加密规则

接口通过 aidEncrypted 参数(即加密后的字符串标识),支持采用加密模式传递验证码业务 CaptchaAppid 进行校验。
当控制台强制校验开启时,触发加密模式。由客户的服端进行加密后下发对应加密字符串到客户的前端,由客户前端将加密后的字符串传参到验证码侧。
加密步骤如下:
1. 登录 验证码控制台,左侧导航栏选择图形验证 > 验证管理,进入验证管理页面。
2. 在验证管理页面,选择所需 AppSecretKey,作为密钥 key。当 key 小于32字节时,循环填充同一个 AppSecretKey 补齐到32字节作为密钥 key。

3. 随机生成16字节的 IV,结合步骤1中得到的密钥 Key,对业务数据对象进行 AES256加密,加密模式为 CBC/PKCS7Padding,加密的业务数据对象为验证码业务 CaptchaAppid&时间戳&密文过期时间,时间戳为秒级当前 unix 时间戳,不可为未来时间,密文过期时间单位为秒最大值为86400秒,得到加密后的串为 CaptchaAppidEncrypted。
4. 对步骤2中 IV 拼接 AES256加密得到的字节数组 CaptchaAppidEncrypted 进行 Base64编码,即 Base64(IV+CaptchaAppidEncrypted),中间无连接符,得到最终加密后的业务参数请求字符串即为 aidEncrypted。

加密结果示例

类型
示例值
Captchaappid
123456789
时间戳
1710144972
过期时间
86400秒
iv
0123456789012345
AppSecretKey
1234567891011121314151516
循环填充的密钥 key
12345678910111213141515161234567
加密的业务数据对象
123456789&1710144972&86400
加密后的最终字符串 aidEncrypted
MDEyMzQ1Njc4OTAxMjM0NWvZ11atw+1uzYmoIyt5rAQVPyMK9ZDavskPw5hcayeT

代码示例

服务端加密
加密规则为:Base64(IV + AES256(CaptchaAppid&时间戳&密文过期时间,IV, Key) ),即使用随机生成16字节的 IV、及根据 AppSecretKey 循环填充后得到32字节的加密 Key,使用 AES256算法加密模式 CBC/PKCS7Padding,对明文数据 CaptchaAppid&时间戳&密文过期时间进行加密。
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from Crypto.Cipher import AES
from Crypto.Util.Padding import pad, unpad
import base64
import time


def encrypt(plaintext, key, iv):
cipher = AES.new(key, AES.MODE_CBC, iv) # 创建一个新的AES cipher,CBC模式
ciphertext = cipher.encrypt(pad(plaintext.encode(), AES.block_size))# 对数据进行填充,然后加密。pad(plaintext.encode(), AES.block_size)将检查明文长度是否为16字节倍数,若非16字节倍数,将使用PKCS7填充方式将明文填充到16字节倍数。
ciphertextBase64 = base64.b64encode(iv + ciphertext).decode('utf-8') # iv拼接加密后的数据,并进行Base64返回后进行传输。
return ciphertextBase64


# 加密示例
AppSecretKey = b'1234567891011121314151516' #客户从控制台获取对应验证码账号下的AppSecretKey,25位
remainder = 32 % AppSecretKey.__len__() # 计算需要补充的密钥长度
key = AppSecretKey + AppSecretKey[:remainder] # 最终加密key,补充满32位。

Captchaappid = "123456789" # 客户自身的验证码CaptchaAppid
curTime = 1710144972 # 获取当前的时间戳,示例暂设置成固定时间戳,客户应该设置成最新的时间戳,使用int(time.time())
expireTime = 86400 # 过期时间设置,这里暂设置成该值,客户根据自身需要设置

plaintext = Captchaappid + "&" + str(curTime) + "&" + str(expireTime) # 拼接待加密的业务数据对象,CaptchaAppid&时间戳&密文过期时间

iv = "0123456789012345".encode() # 随机生成16字节的IV,这里暂设置成该值,客户使用时应该用随机生成的数据,使用os.urandom(16)

ciphertext = encrypt(plaintext, key, iv) # 加密
print("Ciphertext (Base64):", ciphertext) # 本示例数据将输出MDEyMzQ1Njc4OTAxMjM0NWvZ11atw+1uzYmoIyt5rAQVPyMK9ZDavskPw5hcayeT


前端接入示例

const encryptAppid = async () => {
/** 从后端获取加密后的 appid字符串 */
const { aidEncrypted } = await fetch('/api/encryptAppid');
/** 回调函数 */
const callBack = (ret) => {
console.log('ret', ret);
};
/** 错误回调函数 */
const errorCb = (error) => {
console.log('error', error);
};
try {
/** 将获取的加密字符串传入aidEncrypted参数 */
const captcha = new TencentCaptcha('123456789', callBack, { aidEncrypted: aidEncrypted });
captcha.show();
} catch (error) {
errorCb(error);
}
};

常见问题

详情参见 接入相关问题

更多信息

您可以登录 验证码控制台,在页面右上角单击快速咨询,了解更多详细信息。