服务端接入文档
产品通讯流程
正常流程
验证服务正常且用户网络加载正常时验证码流程,服务端需要关注二次验证阶段。

异常流程
验证码自带离线流程
验证服务异常且使用验证码自带的离线模式,服务端需要关注二次验证阶段,此种情况下服务端请求验证码服务会出现异常,建议捕获异常后根据业务场景自行判断是否让用户通过。

自定义降级流程(仅供参考)
验证服务异常且自定义降级验证如字符验证等模式,此种情况下建议服务端新增接口或开关用于前端判定具体验证形式,服务端可通过验证码提供的check_status接口判断验证码是否正常。

服务端验证码集成方案
集成前置准备事项
请根据集成端侧获取所需资源,域名地址等信息请在部署完成后找公司内部对接人获取。
| 端侧类型 | 所需资源 | 资源说明 | 服务端 | captchaId | 验证场景ID,可通过管理后台新建 |
| captchaKey | 验证场景KEY,管理后台新建场景时生成,与captchaId一一对应 |
服务端集成
当用户在前端界面通过验证码后,会产生一批与验证码相关的参数,用户的业务请求带上这些参数,后台业务接口再将这些参数上传到 EngageLab 二次校验接口,确认该用户本次验证的有效性。
以登录场景为例:
- 接入验证码前,前端携带用户名和密码请求业务登录接口,业务方判断用户名和密码是否匹配,匹配成功则登录,匹配失败则拒绝登录;
- 接入验证码后,前端携带业务信息以及验证码相关参数请求业务登录接口,业务方携带验证码相关参数请求验证码服务端二次校验(validate)接口获取验证码判定结果,根据验证码判定结果以及用户名和密码匹配结果结合判定是否允许用户进入后续业务流程。
validate接口说明
| 接口信息 | 说明 |
|---|---|
| 接口地址 | https://captcha-api.engagelab.com/validate |
| 请求方法 | POST |
| 请求格式 | application/json |
| 返回类型 | json |
请求参数
| 参数名 | 类型 | 参数说明 | 参数来源 |
|---|---|---|---|
| lot_number | string | 服务端验证流水号 | 前端传入 |
| captcha_output | string | 验证输出信息 | 前端传入 |
| pass_token | string | 验证通过标识 | 前端传入 |
| gen_time | string | 验证通过时间戳 | 前端传入 |
| captcha_id | string | 验证场景Id | 业务端配置文件,请和前端使用的captchaId保持一致 |
| sign_token | string | 验证签名 | 业务端签名生成,业务端自行生成 |
其中sign_token生成方式如下:
使用用户当前完成验证的流水号lot_number作为原始消息message,使用客户验证私钥captchaKey作为key,采用hmac_sha256散列算法将message和key进行单向散列生成最终的签名
以Java代码为例描述则如下:
String signToken = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, captchaKey).hmacHex(lotNumber);
String signToken = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, captchaKey).hmacHex(lotNumber);
此代码块在浮窗中显示
请求body示例
{
"lot_number": "f26d13345c9980c7705b9111b9398a0f",
"captcha_id": "59bbe0f128f0624fdd185a6a2207aa54",
"sign_token": "2e61e2f6d40e2896b18978fe6ae1416347fc43027ab7c875460d17ffa149dd7a",
"pass_token": "79a4b7fc89d917b346d35286991bc9bca388a78bd31c20fa00907dcb8632611c",
"gen_time": "1684826917",
"captcha_output": "X4oDQ5p61MhE0Zpy5wQcl98WjrDdlDyL5B_VO0zPYnS9ITuz1ZZ6o0iw4Odk9f0AbAlzraqmeLGSmQWHPwJr2Vvf_Nm2Z0SMCn2ATME67e5UhMdopMgc8_zZi-SFRyH1"
}
{
"lot_number": "f26d13345c9980c7705b9111b9398a0f",
"captcha_id": "59bbe0f128f0624fdd185a6a2207aa54",
"sign_token": "2e61e2f6d40e2896b18978fe6ae1416347fc43027ab7c875460d17ffa149dd7a",
"pass_token": "79a4b7fc89d917b346d35286991bc9bca388a78bd31c20fa00907dcb8632611c",
"gen_time": "1684826917",
"captcha_output": "X4oDQ5p61MhE0Zpy5wQcl98WjrDdlDyL5B_VO0zPYnS9ITuz1ZZ6o0iw4Odk9f0AbAlzraqmeLGSmQWHPwJr2Vvf_Nm2Z0SMCn2ATME67e5UhMdopMgc8_zZi-SFRyH1"
}
此代码块在浮窗中显示
响应参数
| 参数名 | 参数类型 | 是否必传 | 参数示例 | 参数说明 |
|---|---|---|---|---|
| status | String | 是 | success | 接口响应状态,success表示接口返回成功 |
| data | Object | 是 | 见data字段说明 | 接口返回成功时返回字段 |
其中data字段说明如下:
| 参数名 | 参数类型 | 是否必传 | 参数示例 | 参数说明 |
|---|---|---|---|---|
| result | String | 是 | success | 二次校验结果,success表示验证通过,其他值表示验证不通过 |
| reason | String | 是 | "" | 校验结果说明 |
| captcha_args | Object | 是 | {} | 返回给客户的信息,主要包括一些策略结果 |
验证码验证通过标识为:响应中status字段为success,同时result字段也为success
其中captcha_args包含的参数如下:
| 参数名 | 参数类型 | 是否必传 | 参数示例 | 参数说明 |
|---|---|---|---|---|
| model_cnn | int | 是 | 0 | CNN滑动轨迹模型判断结果,0表示正常轨迹,1表示异常轨迹 |
| model_probability | int | 是 | 0 | 是否为打码平台请求,0为正常用户,1为打码请求,建议业务实时处理 |
| used_type | String | 是 | slide | 本次使用的验证形式 |
| web_simulator | int | 是 | 0 | 是否为模拟器,0表示正常浏览器,1表示模拟器 |
| user_ip | String | 是 | "127.0.0.1" | 验证通过时用户IP |
| user_referer | String | 是 | "" | 验证通过时用户请求Referer |
| cnn_records | int | 是 | 0 | 整个流程中滑动模型是否有一次预测成非正常轨迹 |
| user_agent | String | 是 | "User-Agent" | 验证通过时用户UA |
| lot_number | String | 是 | "9b57c5289e" | 用户验证流水号 |
注:model_probability为打码标识,当该表示为1时则识别为异常打码请求,建议后续由业务方进行处理。
当data中result字段为success时,表示本次验证结果为通过
响应示例
{
"status": "success",
"data": {
"captcha_args": {
"cnn_records": 0,
"lot_number": "a989b864ad08cc08f270c22d9ab1fba0",
"model_cnn": 0,
"model_probability": 0,
"used_type": "slide",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
"user_ip": "59.174.224.96",
"user_referer": "http://127.0.0.1:5000/",
"web_simulator": 0
},
"reason": "validate success",
"result": "success"
}
}
{
"status": "success",
"data": {
"captcha_args": {
"cnn_records": 0,
"lot_number": "a989b864ad08cc08f270c22d9ab1fba0",
"model_cnn": 0,
"model_probability": 0,
"used_type": "slide",
"user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36",
"user_ip": "59.174.224.96",
"user_referer": "http://127.0.0.1:5000/",
"web_simulator": 0
},
"reason": "validate success",
"result": "success"
}
}
此代码块在浮窗中显示
Java代码接入示例
以业务端使用Java语言开发为例,参考代码如下:
package com.engagelab.demo.controller;
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
import org.json.JSONObject;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
@RestController
public class MainController {
@RequestMapping(value = "/login", method = {RequestMethod.GET})
public String userLogin(@RequestParam Map<String, String> getParams) {
// 1.初始化参数信息,需要与前端使用的captchaId保持一致,也可放在配置文件中
// 1.initialize parameter
String captchaId = "37830cbb24f5a2134d39c7cf3093bc14";
String captchaKey = "ab8aeb88a3c30e170ab04af8ada6e6ec";
// domain为engagelab的验证码服务域名
String domain = "https://captcha-api.engagelab.com";
// 2.获取用户验证后前端传过来的验证流水号等参数
// 2.get the verification parameters passed from the front end after verification
String lotNumber = getParams.get("lot_number");
String captchaOutput = getParams.get("captcha_output");
String passToken = getParams.get("pass_token");
String genTime = getParams.get("gen_time");
// 3.生成签名
// 3.generate signature
// 生成签名使用标准的hmac算法,使用用户当前完成验证的流水号lot_number作为原始消息message,使用客户验证私钥作为key
// use standard hmac algorithms to generate signatures, and take the user's current verification serial number lot_number as the original message, and the client's verification private key as the key
// 采用sha256散列算法将message和key进行单向散列生成最终的签名
// use sha256 hash algorithm to hash message and key in one direction to generate the final signature
String signToken = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, captchaKey).hmacHex(lotNumber);
// 4.上传校验参数到二次验证接口, 校验用户验证状态
// 4.upload verification parameters to the secondary verification interface of EngageLab to validate the user verification status
Map<String, String> queryParams = new HashMap<>();
queryParams.put("captcha_id", captchaId);
queryParams.put("lot_number", lotNumber);
queryParams.put("captcha_output", captchaOutput);
queryParams.put("pass_token", passToken);
queryParams.put("gen_time", genTime);
queryParams.put("sign_token", signToken);
String url = String.format(domain + "/validate");
SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(3000); // 设置连接超时时间
clientHttpRequestFactory.setReadTimeout(1500); // 设置Read超时时间
RestTemplate client = new RestTemplate();
client.setRequestFactory(clientHttpRequestFactory);
JSONObject responseJsonObject = new JSONObject();
//注意处理接口异常情况,当请求二次验证接口异常时做出相应异常处理
// pay attention to interface exceptions, and make corresponding exception handling when requesting secondary verification interface exceptions or response status is not 200
//保证不会因为接口请求超时或服务未响应而阻碍业务流程
// website's business will not be interrupted due to interface request timeout or server not-responding
try {
RequestEntity<Map<String, String>> requestEntity = RequestEntity.post(url).accept(MediaType.APPLICATION_JSON).body(queryParams);
ResponseEntity<String> response = client.exchange(requestEntity, String.class);
String resBody = response.getBody();
responseJsonObject = new JSONObject(resBody);
}catch (Exception e){
// Todo:访问接口超时的情况,请业务方自行处理,demo中默认为验证通过
responseJsonObject.put("status", "success");
responseJsonObject.put("data", new JSONObject("{\"result\": \"success\", \"reason\": \"request captcha api fail\"}"));
}
// 5.根据验证码返回的用户验证状态, 网站主进行自己的业务逻辑
// 5. taking the user authentication status returned from EngageLab into consideration, the website owner follows his own business logic
JSONObject res = new JSONObject();
// 验证码验证通过的判断条件为:1. jsonObject中status字段为success 并且 2. jsonObject中data字段中result属性为success
String status = responseJsonObject.getString("status");
if (status.equals("success")) {
String data = responseJsonObject.getJSONObject("data").getString("result");
if (data.equals("success")) {
res.put("login", "success");
res.put("reason", responseJsonObject.getJSONObject("data").getString("reason"));
} else {
res.put("login", "fail");
res.put("reason", responseJsonObject.getJSONObject("data").getString("reason"));
}
JSONObject captchaArgs = responseJsonObject.getJSONObject("data").getJSONObject("captcha_args");
// 此处获取协议破解识别结果,demo中仅作记录,实际建议业务根据自行业务处理
// model_probability为0表示正常用户,为1表示协议破解即直接通过接口访问(爬虫)
Integer model_probability = captchaArgs.getInt("model_probability");
System.out.println("该接口爬虫识别结果为: " + model_probability);
} else {
// 接口有返回但返回失败,按照验证失败情况处理
res.put("login", "fail");
res.put("reason", "captcha verify fail");
}
return res.toString();
}
}
package com.engagelab.demo.controller;
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
import org.json.JSONObject;
import org.springframework.http.*;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import java.util.HashMap;
import java.util.Map;
@RestController
public class MainController {
@RequestMapping(value = "/login", method = {RequestMethod.GET})
public String userLogin(@RequestParam Map<String, String> getParams) {
// 1.初始化参数信息,需要与前端使用的captchaId保持一致,也可放在配置文件中
// 1.initialize parameter
String captchaId = "37830cbb24f5a2134d39c7cf3093bc14";
String captchaKey = "ab8aeb88a3c30e170ab04af8ada6e6ec";
// domain为engagelab的验证码服务域名
String domain = "https://captcha-api.engagelab.com";
// 2.获取用户验证后前端传过来的验证流水号等参数
// 2.get the verification parameters passed from the front end after verification
String lotNumber = getParams.get("lot_number");
String captchaOutput = getParams.get("captcha_output");
String passToken = getParams.get("pass_token");
String genTime = getParams.get("gen_time");
// 3.生成签名
// 3.generate signature
// 生成签名使用标准的hmac算法,使用用户当前完成验证的流水号lot_number作为原始消息message,使用客户验证私钥作为key
// use standard hmac algorithms to generate signatures, and take the user's current verification serial number lot_number as the original message, and the client's verification private key as the key
// 采用sha256散列算法将message和key进行单向散列生成最终的签名
// use sha256 hash algorithm to hash message and key in one direction to generate the final signature
String signToken = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, captchaKey).hmacHex(lotNumber);
// 4.上传校验参数到二次验证接口, 校验用户验证状态
// 4.upload verification parameters to the secondary verification interface of EngageLab to validate the user verification status
Map<String, String> queryParams = new HashMap<>();
queryParams.put("captcha_id", captchaId);
queryParams.put("lot_number", lotNumber);
queryParams.put("captcha_output", captchaOutput);
queryParams.put("pass_token", passToken);
queryParams.put("gen_time", genTime);
queryParams.put("sign_token", signToken);
String url = String.format(domain + "/validate");
SimpleClientHttpRequestFactory clientHttpRequestFactory = new SimpleClientHttpRequestFactory();
clientHttpRequestFactory.setConnectTimeout(3000); // 设置连接超时时间
clientHttpRequestFactory.setReadTimeout(1500); // 设置Read超时时间
RestTemplate client = new RestTemplate();
client.setRequestFactory(clientHttpRequestFactory);
JSONObject responseJsonObject = new JSONObject();
//注意处理接口异常情况,当请求二次验证接口异常时做出相应异常处理
// pay attention to interface exceptions, and make corresponding exception handling when requesting secondary verification interface exceptions or response status is not 200
//保证不会因为接口请求超时或服务未响应而阻碍业务流程
// website's business will not be interrupted due to interface request timeout or server not-responding
try {
RequestEntity<Map<String, String>> requestEntity = RequestEntity.post(url).accept(MediaType.APPLICATION_JSON).body(queryParams);
ResponseEntity<String> response = client.exchange(requestEntity, String.class);
String resBody = response.getBody();
responseJsonObject = new JSONObject(resBody);
}catch (Exception e){
// Todo:访问接口超时的情况,请业务方自行处理,demo中默认为验证通过
responseJsonObject.put("status", "success");
responseJsonObject.put("data", new JSONObject("{\"result\": \"success\", \"reason\": \"request captcha api fail\"}"));
}
// 5.根据验证码返回的用户验证状态, 网站主进行自己的业务逻辑
// 5. taking the user authentication status returned from EngageLab into consideration, the website owner follows his own business logic
JSONObject res = new JSONObject();
// 验证码验证通过的判断条件为:1. jsonObject中status字段为success 并且 2. jsonObject中data字段中result属性为success
String status = responseJsonObject.getString("status");
if (status.equals("success")) {
String data = responseJsonObject.getJSONObject("data").getString("result");
if (data.equals("success")) {
res.put("login", "success");
res.put("reason", responseJsonObject.getJSONObject("data").getString("reason"));
} else {
res.put("login", "fail");
res.put("reason", responseJsonObject.getJSONObject("data").getString("reason"));
}
JSONObject captchaArgs = responseJsonObject.getJSONObject("data").getJSONObject("captcha_args");
// 此处获取协议破解识别结果,demo中仅作记录,实际建议业务根据自行业务处理
// model_probability为0表示正常用户,为1表示协议破解即直接通过接口访问(爬虫)
Integer model_probability = captchaArgs.getInt("model_probability");
System.out.println("该接口爬虫识别结果为: " + model_probability);
} else {
// 接口有返回但返回失败,按照验证失败情况处理
res.put("login", "fail");
res.put("reason", "captcha verify fail");
}
return res.toString();
}
}
此代码块在浮窗中显示









