通过对比权威数据源，对用户上传的姓名、身份证号进行验证，判断是否为同一个人，返回对比结果。

## 接口说明

该接口返回结果状态分以下两种：

- 认证不通过：表示确认身份证信息不一致，产品可驳回认证申请，不通过的原因可通过ReasonType字段获取。
- 认证通过：表示确认身份证信息完全一致，产品直接通过该认证申请。

### 鉴权说明

易盾信息认证服务使用签名方法对接口进行鉴权，所有接口每一次请求都需要包含签名信息（signature参数），以验证用户身份，防止信息被恶意篡改。目前支持MD5，SHA1，SHA256，SM3几种加密算法，详细信息，请参见[接口鉴权](https://support.dun.163.com/documents/391676076156063744?docId=622572798032863232)

## 请求

### 请求地址

| **名称**      | **值**                                                                                    |
| ----------- | ---------------------------------------------------------------------------------------- |
| HTTP URL    | [http://verify.dun.163.com/v1/idcard/check](http://verify.dun.163.com/v1/idcard/check) |
| HTTP Method | POST                                                                                     |

### 请求头

| **名称**       | **类型** | **必填** | **描述**                                  |
| ------------ | ------ | ------ | --------------------------------------- |
| Content-Type | String | 是      | 固定值："application/x-www-form-urlencoded" |

### 请求参数

请求参数由请求公共参数和请求业务参数两部分组成，通用参数见[请求通用字段](https://support.dun.163.com/documents/391676076156063744?docId=622573136165068800)

| **名称**     | **类 型** | **必填** | 是否支持加密 | **最大长度** | **描述**                                    |
| ---------- | ------- | ------ | ---------- | -------- |-------------------------------------------|
| name       | String  | 是      | 是 | 32       | 用户真实姓名，以身份证上姓名为准                          |
| cardNo     | String  | 是      | 是 | 18       | 用户身份证号码，目前支持一代/二代身份证，号码必须为18位，末尾为x的需要大写为X |
| encryptType | String  | 否      | 否 |          | 加密方式<br/> "3"-SM4加密 "4"-AES加密（目前只支持SM4加密和AES加密，若添加了此字段，**则必须将可加密的字段全部加密，不可只对部分字段加密**） |
| dataId     | String  | 否      | 否 | 64       | 数据标识，可传入用户标识等数据，便于数据查询                    |

### 请求体示例

```other
name=张三&cardNo=xxx&version=v1&businessId=xxx&timestamp=1638180222235&nonce=xxx&secretId=xxx&signature=xxx
```

## 响应

### 响应结果

响应字段如下，响应通用字段已省略，详细见[响应公共字段](https://support.dun.163.com/documents/391676076156063744?docId=624032228347863040)

| **名称**     | **类型** | **必须返回** | **描述**                                                                                                  |
| ---------- | ------ | -------- | ------------------------------------------------------------------------------------------------------- |
| status     | Number | 是        | 认证结果，1-通过 2-不通过（原因见reasonType) 0-待定                                                                     |
| reasonType | Number | 否        | 原因详情  <br/><br/>2-输入姓名和身份证号不一致  <br/><br/>3-查无此身份证  <br/><br/>4-身份证照片信息与输入信息不一致  <br/><br/>7-结果获取失败，请重试<br/><br/>13-交易次数超限或查询过于频繁，请稍后重试 |
| taskId     | String | 是        | 本次请求数据标识，可以根据该标识在[控制台](https://dun.163.com/dashboard#/m/idauth/data/auth/)进行数据查询                        |
| isPayed    | Number | 是        | 本次请求是否收费标识，1代表收费，0代表不收费                                                                                 |

reasonType= 3，查无此身份证。由不可控的多种原因构成： 

（1） 现役或刚退役的军人；

（2） 刚上大学或刚毕业的大学生；

（3） 正在迁移户口或者近期迁移户口；

（4） 工作调动导致户口有迁移；

（5） 发生更名导致户口有变动；

（6） 地方向中心上传时数据缺失。

以上情况无法主动解决，核心库更新速度取决于各地方信息化程度。请接入方提前设计好降级方案，采用白名单、人工审核等方式帮助客户通过验证。

### 响应体示例

```json
{
    "code": 200,
    "msg": "ok",
    "result": {
        "taskId": "079560a6c9f34783bdce47e168510038",
        "status": 2,
        "reasonType": 2,
        "isPayed": 1
    }
}
```

### 响应返回码

响应返回码见：[响应返回码](https://support.dun.163.com/documents/391676076156063744?docId=624032338595143680)

## 加密代码示例

### AES加密代码示例

```java
import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.Key;

public class AESUtils {
    /**
     * 加密
     *
     * @param key  密钥
     * @param data 待加密的明文
     * @return
     * @throws Exception
     */
    public static String encrypt(String key, String data) throws Exception {
        try {
            Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
            Key aesKey = getAesKey(key.getBytes(StandardCharsets.UTF_8));
            c.init(Cipher.ENCRYPT_MODE, aesKey);
            byte[] decValue = c.doFinal(data.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(decValue);
        } catch (Exception e) {
            throw new Exception("encrypt error!", e);
        }
    }

    public static String encrypt(String key, byte[] data) throws Exception {
        Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
        Key aesKey = getAesKey(key.getBytes("UTF-8"));
        c.init(Cipher.ENCRYPT_MODE, aesKey);
        byte[] bytes = c.doFinal(data);
        return bytesToHex(bytes);
    }

    /**
     * 解密
     *
     * @param key  密钥
     * @param data 待解密的密文
     * @return
     * @throws Exception
     */
    public static byte[] decrypt(String key, String data) throws Exception {
        try {
            byte[] decryptData = hexToBytes(data);
            Cipher c = Cipher.getInstance("AES/ECB/PKCS5Padding");
            Key aesKey = getAesKey(key.getBytes(StandardCharsets.UTF_8));
            c.init(Cipher.DECRYPT_MODE, aesKey);
            return c.doFinal(decryptData);
        } catch (Exception e) {
            throw new Exception("decrypt error!", e);
        }
    }

    private static Key getAesKey(byte[] key) {
        return new SecretKeySpec(key, "AES");
    }

    private static String bytesToHex(byte[] bArray) {
        StringBuilder sb = new StringBuilder(bArray.length);
        String sTemp;
        for (int i = 0; i < bArray.length; i++) {
            sTemp = Integer.toHexString(0xFF & bArray[i]);
            if (sTemp.length() < 2) {
                sb.append(0);
            }
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    private static byte[] hexToBytes(String str) {
        if (str == null) {
            return null;
        }
        char[] hex = str.toCharArray();
        int length = hex.length / 2;
        byte[] raw = new byte[length];
        for (int i = 0; i < length; i++) {
            int high = Character.digit(hex[i * 2], 16);
            int low = Character.digit(hex[i * 2 + 1], 16);
            int value = (high << 4) | low;
            if (value > 127) {
                value -= 256;
            }
            raw[i] = (byte) value;
        }
        return raw;
    }

    public static void main(String[] args) throws Exception {
        String key = "12345678912345678912345678912345"; // 易盾分配的密钥
        String data = "12345678912"; // 需要被加密的内容
        String enStr = encrypt(key, data);//加密
        System.out.println(enStr);
    }
}
```



### SM4加密代码示例

```java
import org.apache.commons.codec.binary.Hex;
import org.bouncycastle.jce.provider.BouncyCastleProvider;

import javax.crypto.Cipher;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.security.spec.KeySpec;
import java.util.Base64;

public class SM4Util {

    public static final String ALGORITHM_NAME = "SM4";
    public static final String ALGORITHM_NAME_ECB_PADDING = "SM4/ECB/PKCS5Padding";

    static {
        Security.addProvider(new BouncyCastleProvider());
    }

    /**
     * 加密
     *
     * @param data 需要加密的内容
     * @param key  密钥
     * @return
     */
    public static String encrypt(String data, String key) {
        try {
            byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
            Base64.Decoder decoder = Base64.getDecoder();
            byte[] keyBytes = decoder.decode(key);
            SMS4KeySpec sms4KeySpec = new SMS4KeySpec(keyBytes);

            Cipher cipher = generateECBCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.ENCRYPT_MODE, sms4KeySpec.getKey());

            String encodeSource = Hex.encodeHexString(cipher.doFinal(dataBytes));

            return encodeSource;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    /**
     * 解密
     *
     * @param encrypted 需要解密的内容
     * @param key       密钥
     * @return
     * @throws Exception
     */
    public static String decrypt(String encrypted, String key) throws Exception {
        byte[] cipherText = Hex.decodeHex(encrypted.toCharArray());
        Base64.Decoder decoder = Base64.getDecoder();
        byte[] keyBytes = decoder.decode(key);
        SMS4KeySpec sms4KeySpec = new SMS4KeySpec(keyBytes);

        Cipher cipher = generateECBCipher(ALGORITHM_NAME_ECB_PADDING, Cipher.DECRYPT_MODE, sms4KeySpec.getKey());

        return new String(cipher.doFinal(cipherText), StandardCharsets.UTF_8);
    }

    private static Cipher generateECBCipher(String algorithmName, int mode, byte[] key)
            throws InvalidKeyException, InvalidAlgorithmParameterException, NoSuchAlgorithmException,
            NoSuchProviderException, NoSuchPaddingException {
        Cipher cipher = Cipher.getInstance(algorithmName, BouncyCastleProvider.PROVIDER_NAME);
        Key sm4Key = new SecretKeySpec(key, ALGORITHM_NAME);
        cipher.init(mode, sm4Key);

        return cipher;
    }

    static class SMS4KeySpec implements KeySpec {
        private byte[] key;

        public SMS4KeySpec(byte[] key) throws InvalidKeyException {
            this(key, 0);
        }

        public SMS4KeySpec(byte[] key, int offset) throws InvalidKeyException {
            if (key.length - offset < 16) {
                throw new InvalidKeyException("Wrong key size");
            } else {
                this.key = new byte[16];
                System.arraycopy(key, offset, this.key, 0, 16);
            }
        }

        public byte[] getKey() {
            return (byte[]) ((byte[]) this.key.clone());
        }
    }

    public static void main(String[] args) throws Exception {
        String key = "12345678912345678912345678912345"; // 易盾分配的密钥
        String data = "12345678912"; // 需要被加密的内容
        String enStr = encrypt(data, key);//加密
        System.out.println(enStr);
    }
}
```