# 接入指南

# 平台概述

识蛛慧眼是一组对个人、企业用户身份信息真实性进行验证审核的服务套件,提供各类认证功能模块,包含证件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),签名大体过程如下:

  1. 对所有 API 请求参数(包括公共参数和业务参数,但除去sign参数),根据参数名称的ASCII码表的顺序排序,将排序好的参数名和参数值拼接在一起。
  2. 拼接好的字符串和密钥分别按照UTF-8编码,用编码后的密钥字符流结合HmacSHA256算法对编码后的参数字符流进行摘要。
  3. 将摘要后的字符流转换为十六进制大写字符串,即得到签名值。

# 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 编码(参数顺序可随意,但必须要包括签名参数),然后通过GETPOST发起请求,如:

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=随机数&timestamp=2018-02-07&nbsp;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&timestamp=2018-02-07&nbsp;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
&timestamp=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
&timestamp=2018-02-07 02:50:21
&nonce=随机数
&version=1

<[具体接口特有的请求参数]>

# 响应参数

调用 API 服务后返回数据采用统一格式,code0 ,请求成功,其他为失败,这时没有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配置缺失
最后更新于: 1/28/2021, 4:58:50 PM