身份证介绍demo

对接调试一共分为两部分,一部分为安卓应用对接的SDK,另一部分为应用服务器与商米服务器直接的云对接API。

应用软件集成身份证识别sdk,应用软件后端服务器集成云端api(集成云端api用于保护用户身份信息,保证整个数据链路中,只有应用软件可获取身份证明文信息)

1、终端发起身份证请求,并发送身份证卡片信息到应用软件后台服务器
2、服务器验证卡片真伪,如果为真,返回reqid
3、应用软件收到reqid后,把reqid发送给应用后台服务器
4、应用后台服务器通过openapi把数据发送给商米服务器
5、商米服务器向解码服务器请求解析身份证信息
6、身份证解码服务器返回身份证全部信息的加密数据
7、商米服务器将加密数据返回应用软件后台服务器
8、应用软件服务器解密加密数据后,得到身份证明文数据
9、将明文数据返回应用软件

注:身份证云识别依赖网络,要求每次网络交互过程不得超过200ms,数据交互延迟高于110ms会降低解码成功率(sdk返回9100X错误),高于200ms会造成读卡失败。使用前请确定网络环境满足要求,sdk提供了延迟检测接口,用户可使用延迟检测接口测试网络。不建议使用物联网卡。

1、APP设计和开发

APP设计

APP设计注意要点:android NFC或者读卡器识别到卡片后会有声音提示,身份证读卡操作是个耗时操作,当声音提示后,不能直接拿走卡片,需要等到读卡成功或者失败再拿开卡片。界面上需要提示用户在有明确反馈前不要拿走卡片,建议:loading+文字提示

APP开发

身份证云识别的Android SDK 的集成、初始化、使用流程、网络延迟检测等。

应用发布前,请确保现场网络环境已达要求,否则将影响识别成功率。

1.1、集成

  • 资源文件(AAR文件)

note:v1.1.1版本已经弃用,请用最新版本

1.2、导入AAR包

  • 打开项目后:File -> New -> New Module…
  • 在新的对话框:New Module -> Import .JAR/.AAR Package -> Next
  • 下一步:Import Module from Library -> 选择 aar 文件夹下的 SunmiEID-SDK_vX.X.X-release/tes.aar 文件 -> Finish
  • 完成:

1.3、app 模块引用

  • 点击-打开模块设置:
  • 设置对话框:选择“app” -> 点击“+”号 ->  选择“Module Dependency”
  • 显示:勾选上对应的模块(SunmiEID-SDK_vX.X.X-release/tes)-> 点击“OK”,相关SDK引用成功。

1.4、接口文档

1.4.1、初始化

  • 推荐在Application实现SDK初始化实现:
public class IApp extends Application implements EidCall {
    @Override
    public void onCreate() {
        super.onCreate();
        try {
            EidSDK.init(this, "appid", this);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onTerminate() {
        super.onTerminate();
        EidSDK.destroy();
    }

    @Override
    public void onCallData(int code, String msg) {
        Log.d("app", "onCallData: code:" + code + ", msg:" + msg);
    }
}

1.4.2、获取 EidReader 实例

private void initEidReader() {
    Log.d("Eid", String.format("商米SDK.Ver:%s, 读卡模块Ver:%s", EidSDK.getSunmiEidSDKVersion(), EidSDK.getEidSDKVersion()));
    EidPic.init(this, fileNameBase);
    eid = EidSDK.getEidReaderForNfc(1, this);
}

1.4.3、实现 EidCall 接口

@Override
public void onCallData(int code, String msg) {
    switch (code) {
        case EidConstants.READ_CARD_START:
            mState.setText("开始读卡,请勿移动");
            Log.i(TAG, "开始读卡,请勿移动");
            break;
        case EidConstants.READ_CARD_SUCCESS:
            closeNFCReader();//电子身份证需要关闭
            Log.e("TAG", String.format(Locale.getDefault(), "正在获取身份信息(%s),请稍等.....", msg));
            mState.setText(String.format(Locale.getDefault(), "正在获取身份信息(%s),请稍等.....", msg));
            File file = new File(fileNameBase, "zp.bmp");
            if (file.exists()) {
                file.deleteOnExit();
            }
            getIDCardInfo(msg); //通过card_id请求识读卡片的信息
            break;
        case EidConstants.READ_CARD_FAILED:
            closeNFCReader();//电子身份证需要关闭
            Log.i(TAG, String.format(Locale.getDefault(), "读卡错误,请重新贴卡:%s", msg));
            mState.setText(String.format(Locale.getDefault(), "读卡错误,请重新贴卡:%s", msg));
            break;
        case EidConstants.READ_CARD_DELAY:
            Log.e("TAG", String.format(Locale.getDefault(), "延迟 %sms", msg));
            mState.setText(String.format(Locale.getDefault(), "延迟 %sms", msg));
            break;
        default:
            break;
    }
}

1.4.4、调用NFC识读卡片

  • 识读身份证:
@Override
protected void onNewIntent(Intent intent) {
    super.onNewIntent(intent);
    eid.nfcReadCard(intent);
 }
  • 识读电子身份证:
@Override
    protected void onNewIntent(Intent intent) {
        super.onNewIntent(intent);
        try {
           Tag tagFromIntent = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
           try {
              isodep = IsoDep.get(tagFromIntent);
              isodep.connect();
              if (isodep.isConnected()) {
                  eid.readCard(IDCardType.ECCARD, new EidReadCardCallBack() {
                      @Override
                      public byte[] transceiveTypeB(byte[] data) {
                          return data;
                      }
                      @Override
                      public byte[] transceiveTypeA(byte[] data) {
                          byte[] outData = new byte[data.length];
                          try {
                              outData = isodep.transceive(data);
                          } catch (Exception e) {
                              e.printStackTrace();
                          }
                          return outData;
                      }
                  });
             } else {
                  closeNFCReader()
             }
        } catch (Exception e) {
             e.printStackTrace();
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
 }

    private void closeNFCReader() {
        if (isodep != null) {
            try {
                isodep.close();
                isodep = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

1.5、参考DEMO

注:金融机的NFC功能非安卓标准NFC,需要调用金融SDK进行非接读卡。具体可参考DEMO中的金融读卡内容。

 商米提供了2种不同路径的调用方式:EidCardDemo-OpenApi为端对云的方式,安装apk后输入对应appid和key就可以直接读取身份信息。好处是集成方便,数据路径较短。坏处是安全性没有第二种高。

EidCardDemo为端对云对云的方式,好处是安全性高,坏处是路径较长。

  • 详细处理参考:EidCardDemo (安卓应用首先访问应用服务器,应用服务器通过商米Open Api访问商米服务器进行身份证读取)
  • 直连商米 Open Api 接口:EidCardDemo-OpenApi直连商米open api服务器即安卓应用直接访问商米服务器进行身份证读取。该用法可能会导致appid与appkey同时泄漏,造成损失将由应用商自己承担

1.6、详细接口说明

  • 详细接口文档:

1.7、错误码ErrorCode

2、身份证服务 API 接口

2.1、公共参数说明

2.1.1、概要

请求域名:https://openapi.sunmi.com

openapi的sdk:

golang 版本:https://github.com/sunmi-OS/sunmi-openapi-go-sdk

  1. 商米身份证服务的接口采用 HTTPS 协议
  2. 请求方式统一使用 POST
  3. 请求数据格式为 application/json

2.1.2、公共header说明

  1. 请求必传header

请求公共参数

参数名 类型 说明
Sunmi-Timestamp Integer 当前时间戳
Sunmi-Sign string 签名内容
Sunmi-Nonce Integer 6位随机数
Sunmi-Appid string 申请的APPID

返回公共参数

参数名类型说明
codeInteger返回码,参见公共错误码
dataobject正常返回,如有错误不返回
msgstring错误提示信息,如有错误此字段返回错误描述

2.1.3、签名生成说明

签名算法:hmac256

签名生成方式:

1、拼接stringA(即 stringA=json-body + Sunmi-Appid + Sunmi-Timestamp + Sunmi-Nonce)

2、获取申请的AppKey作为hmac256算法的密钥key

3、最后进行 hmac256(stringA, Appkey)最终获取到sign值

2.1.4、公共错误码

返回码说明
1成功返回
20000网关校验缺少参数
20001请求超过有效期
30000开发者身份验证失败
30001开发者权限不足
40000签名验证失败
40001签名失败
50000服务器异常
50001网关异常

2.2、身份证云识别接口

  • 接口地址:/v2/eid/eid/idcard/decode
  • 请求方式:POST

2.2.1、请求参数

参数名类型说明
request_idstringandroid端生成的 request_id
encrypt_factorstring加密因子(8 位大小写字母和数字组成的的随机字符串,建议每次访问随机生成)

2.2.2、返回参数

成功返回

参数名类型说明
codestring返回码,参见常用错误码表
dataobject返回身份证信息,参见下方 data 域内容
msgstring错误提示信息,如有错误此字段返回错误描述

成功返回 data 域内容

参数名类型说明
infostring身份证信息密文,解密方式参见解密说明

示例:

{
    "code": 1,
    "data": {
        "info": "xxxxxxxxxxxxx"
    },
    "msg": ""
}

失败返回

参数名类型说明
codeInteger返回码,参见常见业务错误码
datastring空字符串
msgstring错误提示信息,如有错误此字段返回错误描述
{
    "code": 20000,
    "data": "",
    "msg": "Missing required parameters"
}

2.2.3、解密说明

  • 加密方式:DES_CBC_PKCS5Padding 加密
  • 加密因子:传入的 encrypt_factor
  • 加密key:开发者平台申请的AppKey

解密流程:

  1. 对 info 字符串 base64 解码(standard 标准解码),解码完为 stringA
  2. 对 stringA 字符串进行 des 解密,截取AppKey前8位作为秘钥key,向量 iv 作为 encrypt_factor 加密因子,解密完为 stringB
  3. stringB 即是身份证信息的 json 格式,内容参见下方身份证云解码信息

身份证云解码信息:

参数名类型说明
base_infoobject身份证基础信息,参见下方身份证基础信息说明
dnstring指纹信息
picturestring身份证头像照片
appeidcodestring应用网络身份标记,同一个身份有一个编码

身份证基础信息:

参数名类型说明
namestring姓名
nationstring民族(如:汉)
sexstring性别(如:男)
idnumstring身份证号码
idTypestring证件类型,见下方证件类型说明
birthDatestring出生年月日(如:20010305)
addressstring身份证住址
beginTimestring身份证有效期限开始时间(如:20180305)
endTimestring身份证有效期限结束时间(如:20180305)
signingOrganizationstring签发机关

示例:

 "base_info": {
      "address": "xx省xx市xxxx路xx号",
      "beginTime": "20180305",
      "endTime": "20180305",
      "birthDate": "20010305",
      "idType": "01",
      "idnum": "xxxxxxx",
      "name": "孙小红",
      "nation": "汉",
      "sex": "男",
      "signingOrganization": "xx市xx公安局"
    },
    "dn": "xxxxxxxxxx",
    "picture": "xxxxxxxxx",
    "appeidcode": "xxxxxxxxx",

 2.2.4、常见业务错误码

返回码说明
50000服务器异常
14200没有权限
14201sdk版本过低
14202无可使用次数
14203读卡错误
14204参数异常