This commit is contained in:
Mrx
2026-05-26 18:09:49 +08:00
parent 28fc40525e
commit 2a33369639
3 changed files with 436 additions and 94 deletions

View File

@@ -1,90 +0,0 @@
自然人公开涉诉信息查询接口文档
接口编码BHSC-P_004_0271
版本V1.0
实施日期2026-04-13
适用场景:合作厂家接入中胜信用平台,用于个人涉诉案件查询(含失信、限高)
1. 通信说明
请求方式HTTP POST
数据格式JSON
编码格式UTF-8
安全要求:请求 IP 需提前绑定
2. 请求信息
请求地址
http://host:port/api/data
请求头Header
表格
参数名 含义 必填 类型 备注
AppCode 接口授权码 Y String 接口服务商提供
pcode 产品编码 Y String 固定值P_004_0271
请求体Body
表格
参数名 含义 必填 类型 说明
name 姓名 Y String 支持明文 / MD5 加密
idCard 身份证号 Y String 支持明文 / MD5 加密
请求示例(明文)
json
{
"idCard": "2103111*****0",
"name": "*****"
}
请求示例(加密)
json
{
"name": "MD5:3e29aae20b7b92775*****",
"idCard": "MD5:a0c28f3a5a*****14"
}
3. 响应信息
表格
字段名 含义 类型 备注
code 状态码 String 参考状态码说明
message 描述信息 String -
orderNo 订单号 String -
pcode 产品编码 String 与请求一致
param 请求参数 Object 原样返回
charge 是否收费 Boolean true = 收费false = 不收费
time 响应时间戳 String 13 位毫秒
data 业务数据 Object 涉诉 / 失信 / 限高数据
响应示例
json
{
"code": "100",
"orderNo": "1361269246899077120",
"charge": true,
"data": {
"ss": {
"preservation": { "count": {} },
"crc": 35****4186,
"cases_tree": {},
"administrative": {},
"civil": {},
"count": {},
"implement": {},
"criminal": {},
"bankrupt": {}
},
"sxbzxr": [{}],
"xgbzxr": []
},
"pcode": "P_004_0271",
"param": null,
"time": "1744593480538",
"message": "查询成功"
}
data 节点说明
ss涉诉案件民事 / 刑事 / 执行 / 行政 / 破产等)
sxbzxr失信被执行人
xgbzxr限制高消费
4. 状态码说明
表格
状态码 描述
100 查询成功
101 参数错误
103 账户不存在
104 IP 限制
105 账号已过期
107 服务不存在
108 产品通道已关闭
109 账户资金不足
110 查询成功,无数据
500 未知请求错误
要不要我帮你把这份接口直接写成可上线的小程序请求代码含加密、header、异常捕获、状态码统一处理

View File

@@ -0,0 +1,432 @@
package huibo
import (
"encoding/base64"
"testing"
)
// 测试 MD5 加密(固定密文对比验证)
func TestMD5Encrypt(t *testing.T) {
appKey := "a6c9935e967894e731c62ecfcd9b7c95"
testCases := []struct {
name string
data string
expected string // 固定密文
}{
{
name: "姓名",
data: "何志勇",
expected: "64d4d5c6457026117a4911acf189e269", // 固定密文
},
{
name: "身份证号",
data: "452528197907133014",
expected: "7c6cc77dabb83d95948904dba5a7219d", // 固定密文
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// 加密
result := MD5Encrypt(tc.data, appKey)
// 最核心:对比是否和固定密文一致
if result != tc.expected {
t.Errorf("加密不匹配!\n明文%s\n期望密文%s\n实际密文%s",
tc.data, tc.expected, result)
return
}
// 打印成功日志
t.Logf("✅ 校验成功\n明文%s\n密文%s", tc.data, result)
})
}
}
// 测试 HMAC-SHA256 签名
func TestHMACSHA256Base64(t *testing.T) {
secret := "test_secret_key"
testCases := []struct {
name string
data string
secret string
}{
{
name: "简单字符串",
data: "hello world",
secret: secret,
},
{
name: "JSON数据",
data: `{"name":"张三","idCard":"110101199003072345"}`,
secret: secret,
},
{
name: "URL参数",
data: "idCard=110101199003072345&name=张三&productCode=22089",
secret: secret,
},
{
name: "空字符串",
data: "",
secret: secret,
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
result := HMACSHA256Base64(tc.data, tc.secret)
// 验证结果不为空
if result == "" {
t.Error("HMAC-SHA256签名结果为空")
}
// 验证结果是有效的Base64
_, err := base64.StdEncoding.DecodeString(result)
if err != nil {
t.Errorf("HMAC-SHA256结果不是有效的Base64: %v", err)
}
// 验证相同输入产生相同输出
result2 := HMACSHA256Base64(tc.data, tc.secret)
if result != result2 {
t.Error("相同输入产生的签名不一致")
}
// 验证不同输入产生不同输出
result3 := HMACSHA256Base64(tc.data+"x", tc.secret)
if result == result3 {
t.Error("不同输入产生的签名相同")
}
t.Logf("数据: %s, 签名: %s", tc.data, result)
})
}
}
// 测试 AES-GCM 加密解密
func TestEncryptDecryptAESGCMBase64(t *testing.T) {
// 生成一个有效的 Base64 编密的 AES 密钥
key := make([]byte, 32) // AES-256
for i := range key {
key[i] = byte(i)
}
base64Key := base64.StdEncoding.EncodeToString(key)
testCases := []struct {
name string
data string
}{
{
name: "简单文本",
data: "hello world",
},
{
name: "中文文本",
data: "你好世界",
},
{
name: "JSON数据",
data: `{"name":"张三","idCard":"110101199003072345"}`,
},
{
name: "长文本",
data: "这是一个很长的文本用来测试加密解密功能是否正常工作。包含各种字符123456789!@#$%^&*()_+-=[]{}|;':\",./<>?",
},
{
name: "空字符串",
data: "",
},
{
name: "特殊字符",
data: "\n\t\r\x00",
},
}
for _, tc := range testCases {
t.Run(tc.name, func(t *testing.T) {
// 加密
encrypted, err := EncryptAESGCMBase64(tc.data, base64Key)
if err != nil {
t.Fatalf("加密失败: %v", err)
}
// 验证加密结果不为空
if encrypted == "" {
t.Error("加密结果为空")
}
// 验证加密结果是有效的Base64
_, err = base64.StdEncoding.DecodeString(encrypted)
if err != nil {
t.Errorf("加密结果不是有效的Base64: %v", err)
}
// 验证加密结果与原文不同
if encrypted == tc.data {
t.Error("加密结果与原文相同")
}
// 解密
decrypted, err := DecryptAESGCMBase64(encrypted, base64Key)
if err != nil {
t.Fatalf("解密失败: %v", err)
}
// 验证解密结果与原文一致
if decrypted != tc.data {
t.Errorf("解密结果不匹配,期望: %s, 实际: %s", tc.data, decrypted)
}
t.Logf("原文: %s", tc.data)
t.Logf("密文: %s", encrypted)
t.Logf("解密: %s", decrypted)
})
}
}
// 测试错误的密钥
func TestEncryptDecryptWithWrongKey(t *testing.T) {
// 生成两个不同的密钥
key1 := make([]byte, 32)
for i := range key1 {
key1[i] = byte(i)
}
base64Key1 := base64.StdEncoding.EncodeToString(key1)
key2 := make([]byte, 32)
for i := range key2 {
key2[i] = byte(i + 1)
}
base64Key2 := base64.StdEncoding.EncodeToString(key2)
data := "sensitive data"
// 用密钥1加密
encrypted, err := EncryptAESGCMBase64(data, base64Key1)
if err != nil {
t.Fatalf("加密失败: %v", err)
}
// 用密钥2解密
decrypted, err := DecryptAESGCMBase64(encrypted, base64Key2)
if err == nil {
t.Error("用错误密钥解密应该返回错误")
}
// 验证解密结果与原文不同(如果解密成功的话)
if decrypted == data {
t.Error("用错误密钥解密不应该得到正确结果")
}
t.Logf("用错误密钥解密预期失败: %v", err)
}
// 测试无效的 Base64 密钥
func TestEncryptWithInvalidBase64Key(t *testing.T) {
data := "test data"
invalidKeys := []string{
"", // 空字符串
"not_base64", // 非Base64
"abc", // 解码后太短
}
for _, invalidKey := range invalidKeys {
_, err := EncryptAESGCMBase64(data, invalidKey)
if err == nil {
t.Errorf("使用无效密钥 %s 应该返回错误", invalidKey)
}
t.Logf("无效密钥 %s 预期失败: %v", invalidKey, err)
}
}
// 测试解密无效数据
func TestDecryptWithInvalidData(t *testing.T) {
// 生成一个有效的密钥
key := make([]byte, 32)
for i := range key {
key[i] = byte(i)
}
base64Key := base64.StdEncoding.EncodeToString(key)
invalidData := []string{
"", // 空字符串
"invalid_base64", // 非Base64
"dGVzdA==", // 有效的Base64但不是AES-GCM数据
"short", // 太短
}
for _, data := range invalidData {
_, err := DecryptAESGCMBase64(data, base64Key)
if err == nil {
t.Errorf("使用无效数据 %s 应该返回错误", data)
}
t.Logf("无效数据 %s 预期失败: %v", data, err)
}
}
// 测试加密结果的唯一性
func TestEncryptionUniqueness(t *testing.T) {
// 生成一个有效的密钥
key := make([]byte, 32)
for i := range key {
key[i] = byte(i)
}
base64Key := base64.StdEncoding.EncodeToString(key)
data := "same data"
// 加密多次
results := make([]string, 10)
for i := 0; i < 10; i++ {
encrypted, err := EncryptAESGCMBase64(data, base64Key)
if err != nil {
t.Fatalf("第%d次加密失败: %v", i, err)
}
results[i] = encrypted
}
// 验证每次加密结果都不同因为包含随机IV
uniqueCount := 0
for i := 0; i < len(results); i++ {
isUnique := true
for j := 0; j < len(results); j++ {
if i != j && results[i] == results[j] {
isUnique = false
break
}
}
if isUnique {
uniqueCount++
}
}
if uniqueCount != len(results) {
t.Errorf("加密结果应该唯一,实际上只有%d个唯一结果期望%d个", uniqueCount, len(results))
}
t.Logf("生成了%d个不同的加密结果", uniqueCount)
}
// 测试使用真实配置的加密解密
func TestEncryptionWithRealConfig(t *testing.T) {
// 使用配置文件中的真实AES密钥
aesKey := "NQYN3YO+pb/GEcCBNX0ptMb7cUlnXSPvcX7VvNofBkc="
appKey := "a6c9935e967894e731c62ecfcd9b7c95"
// 测试数据
testData := `{"name":"张三","idCard":"110101199003072345","productCode":"22089"}`
t.Run("MD5加密", func(t *testing.T) {
// 测试 MD5 加密
md5Result := MD5Encrypt("张三", appKey)
t.Logf("姓名 MD5: %s", md5Result)
md5Result2 := MD5Encrypt("110101199003072345", appKey)
t.Logf("身份证号 MD5: %s", md5Result2)
// 验证格式
if len(md5Result) != 32 {
t.Errorf("MD5结果长度错误期望32位实际%d位", len(md5Result))
}
})
t.Run("HMAC-SHA256签名", func(t *testing.T) {
// 生成排序后的参数
sortedParam := "idCard=110101199003072345&name=张三&productCode=22089"
signature := HMACSHA256Base64(sortedParam, aesKey)
t.Logf("签名参数: %s", sortedParam)
t.Logf("HMAC-SHA256签名: %s", signature)
// 验证格式
_, err := base64.StdEncoding.DecodeString(signature)
if err != nil {
t.Errorf("签名不是有效的Base64: %v", err)
}
})
t.Run("AES-GCM加密解密", func(t *testing.T) {
// 测试 AES-GCM 加密
encrypted, err := EncryptAESGCMBase64(testData, aesKey)
if err != nil {
t.Fatalf("加密失败: %v", err)
}
t.Logf("原始数据: %s", testData)
t.Logf("加密结果: %s", encrypted)
// 测试解密
decrypted, err := DecryptAESGCMBase64(encrypted, aesKey)
if err != nil {
t.Fatalf("解密失败: %v", err)
}
t.Logf("解密结果: %s", decrypted)
// 验证结果
if decrypted != testData {
t.Errorf("解密结果不匹配")
}
})
}
// 基准测试
func BenchmarkMD5Encrypt(b *testing.B) {
data := "张三"
appKey := "a6c9935e967894e731c62ecfcd9b7c95"
b.ResetTimer()
for i := 0; i < b.N; i++ {
MD5Encrypt(data, appKey)
}
}
func BenchmarkHMACSHA256Base64(b *testing.B) {
data := "idCard=110101199003072345&name=张三"
secret := "a6c9935e967894e731c62ecfcd9b7c95"
b.ResetTimer()
for i := 0; i < b.N; i++ {
HMACSHA256Base64(data, secret)
}
}
func BenchmarkEncryptAESGCMBase64(b *testing.B) {
data := `{"name":"张三","idCard":"110101199003072345","productCode":"22089"}`
// 生成密钥
key := make([]byte, 32)
for i := range key {
key[i] = byte(i)
}
base64Key := base64.StdEncoding.EncodeToString(key)
b.ResetTimer()
for i := 0; i < b.N; i++ {
EncryptAESGCMBase64(data, base64Key)
}
}
func BenchmarkDecryptAESGCMBase64(b *testing.B) {
data := `{"name":"张三","idCard":"110101199003072345","productCode":"22089"}`
// 生成密钥
key := make([]byte, 32)
for i := range key {
key[i] = byte(i)
}
base64Key := base64.StdEncoding.EncodeToString(key)
// 先加密一次
encrypted, err := EncryptAESGCMBase64(data, base64Key)
if err != nil {
b.Fatalf("预加密失败: %v", err)
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
DecryptAESGCMBase64(encrypted, base64Key)
}
}