# 接入指南
# 平台概述
识蛛慧眼是一组对个人、企业用户身份信息真实性进行验证审核的服务套件,提供各类认证功能模块,包含证件OCR识别、活体检测、人脸1:1对比、企业工商四要素核验、对公打款认证等能力,以解决行业内大量对个人、企业用户身份信息核实的需求,广泛应用于金融、运营商、共享出行等领域。
# 产品介绍
- 实名认证:主要用于对申请用户身份信息进行认证,核实用户的姓名和身份证号是否真实匹配,存在,从而有效防止身份造假,确保用户身份真实存在。
- 图片OCR识别:提供对身份证照片等证件的识别服务。
- 人脸验证:验证当前采集的人像是否与身份证芯片照为同一人。
- 活体信息验证:用户在打开摄像头时,需要根据提示进行互动操作(例如,凝视屏幕,摇头,眨眼睛等动作),从而达到鉴别真人的目的,可有效抵御照片,换脸,面具,遮挡以及屏幕翻拍等常见的攻击手段,从而帮助用户甄别欺诈行为,保障用户的利益。
- 手机号实名认证:主要验证用户,身份证,电话号是否为同一人。
- 企业意愿认证:通过短信认证,文件上传审核,对公打款及人脸活体检测等方式,核实企业认证意愿。
# 基础概念解释
1、公共参数: 公共请求参数是指每个接口都需要使用到的请求参数,与业务无关;
2、业务参数: 根据调用API服务接口的需求所传递的参数;
3、签名算法: 签名算法是指数字签名的算法。数字签名(又称公钥数字签名、电子签章)是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。
4、表单: 在网页中主要负责数据采集功能。一个表单有三个基本组成部分: 表单标签:这里面包含了处理表单数据所用CGI程序的URL以及数据提交到服务器的方法。 表单域:包含了文本框、密码框、隐藏域、多行文本框、复选框、单选框、下拉选择框和文件上传框等。 表单按钮:包括提交按钮、复位按钮和一般按钮;用于将数据传送到服务器上的CGI脚本或者取消输入,还可以用表单按钮来控制其他定义了处理脚本的处理工作。
# API签名算法
认证平台的 API 是基于 HTTP(S) 协议来调用的,开发者可以直接使用我们提供的SDK(包含了请求的封装,签名加密,响应解释等)来调用, 以下主要是针对自行封装 HTTP(S) 请求进行API调用的签名算法进行详细解说。API调用除了必须包含公共参数外,API本身业务级的参数
,每个API的业务级参数请参考API文档说明。
# 签名算法原理
为了防止 API 调用过程中被恶意篡改,调用任何一个 API 都需要携带签名,服务端会根据请求参数,对签名进行验证,签名不合法的请求将会被拒绝。目前支持的签名算法:HMAC-SHA256(signMethod=HMAC-SHA256),签名大体过程如下:
- 对所有 API 请求参数(包括公共参数和
业务参数
,但除去sign参数),根据参数名称的ASCII码表的顺序排序,将排序好的参数名和参数值拼接在一起。 - 拼接好的字符串和密钥分别按照UTF-8编码,用编码后的密钥字符流结合HmacSHA256算法对编码后的参数字符流进行摘要。
- 将摘要后的字符流转换为
十六进制大写字符串
,即得到签名值。
# JAVA 签名示例代码
姓名实名认证签名例子:
请求示例:
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.UnsupportedEncodingException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* 获取参数签名
* @author 慧眼个人/企业认证
*/
public class GetSignature {
/**密钥*/
private static String secretKey = "XXX";
private static String charset = "UTF-8";
private static final String TIMESTAMP_FORMAT = "yyyy-MM-dd HH:mm:ss";
private static final String ALGORITHM = "HmacSHA256";
private static final Object LOCK = new Object();
private static Mac macInstance;
public static void main(String[] args) {
Map<String, String> paramMap = new HashMap<String, String>(10);
//公共参数
paramMap.put("appKey", "XXX");
paramMap.put("signMethod", "HMAC-SHA256");
paramMap.put("signVersion", "1");
paramMap.put("method", "XXX");
paramMap.put("format", "JSON");
paramMap.put("timestamp", getTime());
paramMap.put("version", "1");
paramMap.put("nonce", getNonce());
//具体接口参数,如姓名实名认证
paramMap.put("realname", "XXX");
paramMap.put("idcard", "XXX");
//获取待签名内容,排序
String signContent = getSignatureContent(paramMap);
System.out.println("待签名内容:" + signContent);
//计算签名
String sign = computeSignature(secretKey, signContent, charset);
System.out.println("签名后:" + sign);
}
/**
* 格式化时间
*/
private static String getTime() {
TimeZone tz = TimeZone.getTimeZone("UTC");
DateFormat df = new SimpleDateFormat(TIMESTAMP_FORMAT);
df.setTimeZone(tz);
return df.format(new Date());
}
/**
* 生成随机数
*/
private static String getNonce(){
Random random = new Random();
return String.valueOf(random.nextInt(1000000000));
}
/**
* 将参数按key值排序
*/
public static String getSignatureContent(Map<String, String> paramMap) {
Collection<String> keySet = paramMap.keySet();
//签名内容
StringBuilder content = new StringBuilder();
//所有的键值
List<String> keys = new ArrayList<String>(keySet);
//排序
Collections.sort(keys);
//循环赋值
for (String key : keys) {
String value = paramMap.get(key);
if (isNotEmpty(key) && isNotEmpty(value)) {
content.append(key).append(value);
}
}
return content.toString();
}
/**
*字符串非空校验
*/
private static boolean isNotEmpty(String str) {
return str != null && str.length() != 0;
}
/**
* 计算签名值
*/
private static String computeSignature(String key, String data, String charset) {
try {
byte[] signData = sign(key.getBytes(charset), data.getBytes(charset));
return byte2hex(signData);
} catch (UnsupportedEncodingException ex) {
throw new RuntimeException("不支持的算法: " + charset, ex);
}
}
/**
* 把字节流转换为十六进制表示方式。
*/
private static String byte2hex(byte[] bytes) {
StringBuilder sign = new StringBuilder();
for (int i = 0; i < bytes.length; i++) {
String hex = Integer.toHexString(bytes[i] & 0xFF);
if (hex.length() == 1) {
sign.append("0");
}
sign.append(hex.toUpperCase());
}
return sign.toString();
}
/**
* 使用HMAC加密
*/
private static byte[] sign(byte[] key, byte[] data) {
try {
//因为Mac类的getInstance()方法的调用时一个同步方法,可能被阻塞,所以使用原型模式来提高可靠性
if (macInstance == null) {
synchronized (LOCK) {
if (macInstance == null) {
macInstance = Mac.getInstance(ALGORITHM);
}
}
}
Mac mac;
try {
mac = (Mac) macInstance.clone();
} catch (CloneNotSupportedException e) {
//如果不可复制,创建一个新的Mac对象
mac = Mac.getInstance(ALGORITHM);
}
mac.init(new SecretKeySpec(key, ALGORITHM));
return mac.doFinal(data);
} catch (NoSuchAlgorithmException ex) {
throw new RuntimeException("不支持的算法: " + ALGORITHM, ex);
} catch (InvalidKeyException ex) {
throw new RuntimeException("非法key: " + key, ex);
}
}
}
详细示例代码请参见 SDK 源代码。
# 调用示例
1、设置参数值
format = "JSON"
version = "1"
appKey = "1111111"
signMethod = "HMAC-SHA256"
signVersion = "1"
signVersion = "1"
timestamp = "2018-02-07 02:50:21"
nonce = "随机数"
realname = "张三"
idcard = "111111111111111111"
2、排序
appKey = "1111111"
format = "JSON"
idcard = "111111111111111111"
method = "realid.idcard.verify"
nonce ="随机数"
realname = "张三"
signMethod = "HMAC-SHA256"
signVersion = "1"
timestamp = "2018-02-07 02:50:21"
version = "1"
3、拼接参数名与参数值
appKey1111111formatJSONidcard111111111111111111methodrealid.idcard.verifynonce1111111 realname张三signMethodHMAC-SHA256signVersion1timestamp2018-02-07 02:50:21version1
4、生成签名
假设 secretKey 为 111111,则签名结果为: E41E6FDA4D24B27AE78281F6D71D790F55097CD558BB377A3F9343F07ADED112
# API调用协议
接口支持HTTP,HTTPS GET/POST请求,所有接口需在请求中加入公共参数,请求及返回结果都使用 UTF-8 字符集进行编码。
组装 HTTP(S) 请求
将所有参数名和参数值采用UTF-8进行 URL 编码(参数顺序可随意,但必须要包括签名参数),然后通过GET
或POST
发起请求,如:
HTTP GET请求
http://api.spiderid.cn/api/router/rest?appKey=1111111&format=JSON&method=realid.idcard.verify&signMethod=HMAC-SHA256&signVersion=1&version=1&realname=张三&idcard=111111111111111111&nonce=随机数×tamp=2018-02-07 02:50:21&sign=E41E6FDA4D24B27AE78281F6D71D790F55097CD558BB377A3F9343F07ADED112
HTTPS POST请求
:
https://api.spiderid.cn/api/router/rest?appKey=1111111&format=JSON&method=realid.idcard.verify&signMethod=HMAC-SHA256&signVersion=1&version=1&nonce=1111111×tamp=2018-02-07 02:50:21&sign=E41E6FDA4D24B27AE78281F6D71D790F55097CD558BB377A3F9343F07ADED112
realname=张三&idcard=111111111111111111
# 注意事项
1、所有的请求和响应数据编码皆为UTF-8格式,URL 里的所有参数名和参数值请做 URL 编码。如果请求的 Content-Type 是 application/x-www-form-urlencoded,则 HTTP Body 体里的所有参数值也做 URL 编码;如果是 multipart/form-data 格式,每个表单字段的参数值无需编码, 但每个表单字段的 charset 部分需要指定为UTF-8。
2、参数名与参数值拼装起来的 URL 长度小于 1024 个字符时,可以用 GET 发起请求;参数类型含 byte[] 类型或拼装好的请求 URL 过长时,必须用 POST 发起请求。所有 API 都可以用 POST 发起请求,某些 API 只支持 POST 请求
。
3、POST请求请务必将业务参数放入请求Body中
# 公共参数
公共请求参数是指每个接口都需要使用到的请求参数,务必以url参数形式传入
名称 | 类型 | 是否必须 | 描述 |
---|---|---|---|
appKey | String | 是 | 身份标识,注册后获得 |
sign | String | 是 | 签名结果串,请参看API签名机制 |
signMethod | String | 是 | 签名算法,默认HMAC-SHA256 |
signVersion | String | 是 | 签名算法版本,目前是1 |
method | String | 是 | 服务方法/API接口名称 |
format | String | 是 | 返回值的类型,默认JSON |
timestamp | String | 是 | 时间戳,日期格式按照 ISO8601 标准表示,并需要使用 UTC 时间。格式为 yyyy-MM-dd HH:mm:ss |
nonce | String | 是 | 唯一随机数,同样的值,10分钟内只能被使用一次 |
version | String | 是 | API 版本号,目前版本是1 |
请求示例:
GET:
http://api.spiderid.cn/api/router/rest?
&appKey=XXX
&sign=XXX
&signMethod=HMAC-SHA256
&signVersion=1
&method=XXX
&format=JSON
×tamp=2018-02-07 02:50:21
&nonce=随机数
&version=1
&<[具体接口特有的请求参数]>
POST:
http://api.spiderid.cn/api/router/rest?
&appKey=XXX
&sign=XXX
&signMethod=HMAC-SHA256
&signVersion=1
&method=XXX
&format=JSON
×tamp=2018-02-07 02:50:21
&nonce=随机数
&version=1
<[具体接口特有的请求参数]>
# 响应参数
调用 API 服务后返回数据采用统一格式,code
为0
,请求成功,其他为失败,这时没有data结果信息
名称 | 类型 | 描述 |
---|---|---|
code | Integer | 状态码,0 请求成功,其他为失败,具体见 API错误码说明 |
requestId | String | 请求唯一标识 |
message | String | 状态码的描述 |
data | Object | 结果信息,code为0时出现,具体看各个接口说明 |
# 成功示例
JSON示例
{
"code": 0,
"requestId": "dsd24...",
"data": {
......
},
"message": "success"
}
# 失败示例
JSON示例
{
"code": 10008,
"requestId": "f1001ac1224...",
"message": "App不存在或状态异常"
}
# API错误码说明
# 错误码解释
返回码 | 系统错误 | 备注 |
---|---|---|
10001 | 系统错误 | |
10002 | 服务异常,请联系客服 | |
10003 | 远程服务错误 | |
10004 | 平台系统维护 | |
10005 | 请求参数(XX)XX,请参考API文档 | (如:请求参数(name)不合法,请参考API文档) |
10006 | 请求参数非法,请参考API文档 | |
10007 | 签名算法XX不支持 | (如:签名算法HMAC-SHA1不支持) |
10008 | App不存在或状态异常 | |
10009 | App签名错误 | |
10010 | 请求重复 | |
10011 | 请求过期 | |
10012 | 没有访问此接口权限 | |
10013 | 请求IP(XX)不在允许访问接口白名单 | (如:请求IP(127.0.0.1)不在允许访问接口白名单) |
10014 | 请求超时 | |
10015 | API超过最大可访问次数 | |
10016 | App已被禁用 | |
10017 | 服务限流 | |
10018 | 余额不足 | |
10019 | 账户已冻结 | |
10020 | 请求数据过大 | |
10021 | 该服务已经下架 | |
10022 | 核验中心系统错误 | |
10023 | 认证记录不存在 | |
10024 | 认证状态非法 | |
10025 | 认证场景非法 | |
10026 | 核验中心系统维护 | |
10027 | tsp错误 | |
10028 | evc错误 | |
10029 | 身份未认证 | |
10030 | 用户缺失身份参数 | |
10031 | 用户类型非法 | |
10032 | API不存在 | |
10033 | App配置缺失 |