运营商三要素简版MD5接口文档
更新时间:2025-08-18
接口描述
本接口为三要素实名制验证详版接口
接口地址
见已购列表
返回格式:json
请求方式:post
接口签名说明
准备签名参数字符串str_for_sign:
请求参数按参数名字典排序(字典序)后,按name1=value1&name2=value2&…
字典序:在英文字典中,排列单词的顺序是先按照第一个字母以升序排列(即a、b、c……z 的顺序);如果第一个字母一样,那么比较第二个、第三个乃至后面的字母。如果比到最后两个单词不一样长(比如,sigh 和 sight),那么把短者排在前。
准备签名参数字符串paramEncrypt:
该字符串是加密所得,比如reqEncryptType为1时,意味着AES加密(目前只支持AES加密)
使用secretKey作为加密密钥,加密前字符串为parameters中的所需参数,如"{"mobile":"xxxxxxxx"}" (根据接口不一样,参数也不一样)
AES加密的密钥长度:32位字符串,对应128位二进制数据;
AES加密的加密模式:aes-128-ecb
JAVA AES加密示例:
                Plain Text
                
            
            1Map<String, Object> paramMap = new HashMap<>();
2paramMap.put("mobile", mobile);
3String s = JSON.toJSONString(paramMap);
4String encrypt = AesEncryptUtil.encrypt(s, {secretKey});
5
6public static String encrypt(String content, String encryptKey) {
7    String key = encryptKey;
8    if (encryptKey.length() > 64) {
9        key = encryptKey.substring(0, DEFAULT_KEY_LEN);
10    }
11    try {
12        Cipher cipher = Cipher.getInstance("AES");
13        cipher.init(Cipher.ENCRYPT_MODE, new SecretKeySpec(key.getBytes("utf-8"), "AES"));
14        byte[] b = cipher.doFinal(content.getBytes("utf-8"));
15        return Base64.encodeBase64String(b);
16    } catch (Exception e) {
17        log.info("AesEncryptUtil encrypt catch e: {}", e);
18        return null;
19    }
20
21}
            signature= Md5((str_for_sign+'&')+(paramEncrypt+'&')+timestamp+'&'+secretKey),其中secretKey 是系统获取的sk 注意:参数值为空不需要参与签名,如str_for_sign为空字符串,则直接省去(str_for_sign+'&') 如果采用aes加密,则不需要(str_for_sign+'&'),如果不采用aes加密,则不需要(paramEncrypt+'&')
请求头Header参数
| 参数名称 | 类型 | 是否必选 | 参数描述 | 示例 | 
|---|---|---|---|---|
| appkey | String | 是 | 应用key,在控制台中查看,不可以直接用示例 | 207xxx | 
| timestamp | String | 是 | 时间戳,单位秒 | 1667810816 | 
| signature | String | 是 | 签名 | e06fa22f57fd5c9e9138f183d59b18a | 
请求体Body参数
| 参数名称 | 类型 | 是否必选 | 参数描述 | 示例 | 
|---|---|---|---|---|
| parameters | JSON | 否 | 如果新增paramEncrypt、reqEncryptType参数,则不需要传该参数 | "parameters": {"name":"xxx","idNum":"xxx","mobile":"xxx"} | 
| paramEncrypt | String | 否 | 加密后的请求参数(就是将就是将上述的{"name":"xxx","idNum":"xxx","mobile":"xxx"}进行一次加密,并放入paramEncrypt属性中,详见上文准备签名参数字符串paramEncrypt) | Ht8YMQtfxHplmfPn2BcXXZtE0lN2NGHKEgQrHO5W1/qREKpHOmj21N8uInLRDLxx | 
| reqEncryptType | String | 否 | 入参加密类型 默认为0-不加密;1-AES加密 | 0 | 
注意事项
请注意,以上参数,假设paramEncrypt+reqEncryptType为A组,parameters为B组,A B组必须存在其一,且不可同时存在
- 如果采取入参aes加密,则reqEncryptType、paramEncrypt都需要传递,且reqEncryptType为1;parameters参数不需要传递
 - 如果不需要采用入参加密,则传递parameters参数,reqEncryptType、paramEncrypt不需要传递
 
请求体中parameters参数
| 参数名称 | 类型 | 是否必选 | 参数描述 | 示例 | 
|---|---|---|---|---|
| name | String | 是 | 姓名-MD5加密 | 王xx | 
| idNum | String | 是 | 身份证号-MD5加密 | xxxxxxxxx | 
| mobile | String | 是 | 手机号-MD5加密 | 188xxxxxxx | 
请求体示例
                Plain Text
                
            
            1#明文请求
2{
3    "parameters": {"name":"{姓名MD5大写}","idNum":"{身份证号MD5大写}","mobile":"{手机号MD5大写}"}}
4}
5#AES加密请求(就是将上述的{"name":"{姓名}","idNum":"{身份证号}","mobile":"{手机号}"}进行一次加密,并放入paramEncrypt属性中:)
6{
7 "paramEncrypt":"Ht8YMQtfxHplmfPn2BcXXZtE0lN2NGHKEgQrHO5W1/qREKpHOmj21N8uInLRDLeO",
8 "reqEncryptType":1
9}
            响应参数
| 参数名称 | 类型 | 是否存在 | 参数描述 | 示例 | 
|---|---|---|---|---|
| code | String | 是 | 响应码 | 01 | 
| data | json | 是 | 响应数据 | xxxxxxxxx | 
| message | String | 是 | 响应详细 | 成功 | 
data参数
| 参数名称 | 类型 | 是否存在 | 参数描述 | 示例 | 
|---|---|---|---|---|
| id | String | 是 | pnvs响应id | 971961d8ffce4669b75c35fb46738843 | 
| responseParams | json | 是 | 响应参数(非必传,字段可能会变化,建议不要使用) | |
| statusType | String | 是 | 业务状态 | “业务成功” | 
响应体示例
                Plain Text
                
            
            1{
2   "code":"01",
3   "data":{
4           "id":"896487b984e14a9382b384a5d37f7fa5",
5           "statusType":"业务成功"
6      },
7   "message":"验证成功,一致"
8}
            调用示例
                Plain Text
                
            
            1@Test
2public void testTelecomApi() {
3    String localUrl = "见已购列表";
4    InvokeRequest invokeRequest = new InvokeRequest();
5
6    Long timestamp = System.currentTimeMillis() / 1000;
7    Map<String, Object> paramMap = new HashMap<>();
8
9    paramMap.put("mobile", "手机号");
10    paramMap.put("name", "姓名");
11    paramMap.put("idNum", "身份证号");
12    invokeRequest.setParameters(paramMap);
13    String secretKey = "提供的sk";
14    StringBuilder assemble = AssembleUtil.assembleParameters(paramMap);
15    assemble.append(timestamp).append("&").append(secretKey);
16    String signature = md5Encode(assemble.toString());
17    String bodyJson = JSON.toJSONString(invokeRequest);
18    List<Header> headers = new ArrayList<>();
19    Header appKeyHeader = new BasicHeader("appkey", "提供的ak");
20    Header timeStampHeader = new BasicHeader("timestamp",
21            String.valueOf(timestamp));
22    Header msgEncryptionHeader = new BasicHeader("signature", signature);
23    headers.add(appKeyHeader);
24    headers.add(timeStampHeader);
25    headers.add(msgEncryptionHeader);
26    System.out.println(HttpsUtil.post(localUrl, headers.toArray(new Header[]{}), bodyJson,
27            2000, 30000));
28}
29
30
31
32// assemble方法
33public class AssembleUtil {
34    public static <T> StringBuilder assembleParameters(Map<String, T> paramMap) {
35        StringBuilder result = new StringBuilder();
36        if (paramMap == null || paramMap.isEmpty()) {
37            return result;
38        }
39
40        paramMap.entrySet().stream().sorted(Comparator.comparing(Map.Entry::getKey)).forEach(entry ->
41                result.append(entry.getKey()).append("=").append(entry.getValue()).append("&"));
42        return result;
43    }
44}
45
46// md5方法
47public static String md5Encode(String plainText) {
48    byte[] secretBytes;
49    try {
50        secretBytes = MessageDigest.getInstance("md5").digest(plainText
51                .getBytes());
52    } catch (NoSuchAlgorithmException e) {
53        throw new RuntimeException("无此md5算法");
54    }
55    String md5code = (new BigInteger(1, secretBytes)).toString(16);
56    return StringUtils.leftPad(md5code, 32, "0");
57}
            