add ivyz9k2l

This commit is contained in:
2025-11-20 20:16:18 +08:00
parent a53727757c
commit 7fc072e608
4 changed files with 309 additions and 12 deletions

View File

@@ -0,0 +1,261 @@
# IVYZ9K2L - 身份认证三要素(人脸图像版) WestDex API 文档
## 接口信息
- **接口名称**: 身份认证三要素(人脸图像版)
- **接口代码**: IVYZ9K2L
- **WestDex API Code**: `idCardThreeElements`
- **请求方式**: POST
- **Content-Type**: application/json
## 请求URL
```
https://apimaster.westdex.com.cn/api/invoke/{secret_id}/{api_code}?timestamp={timestamp}
```
### URL 参数说明
| 参数 | 说明 | 示例值 |
|------|------|--------|
| secret_id | 西部数据 SecretID从配置获取 | `449159` |
| api_code | API代码 | `idCardThreeElements` |
| timestamp | 毫秒级时间戳URL参数 | `1713421668375` |
### 完整URL示例
```
https://apimaster.westdex.com.cn/api/invoke/449159/idCardThreeElements?timestamp=1713421668375
```
## 请求头
```
Content-Type: application/json
```
## 请求体
### 请求体结构
```json
{
"data": {
"timeStamp": "1713421668375",
"customNumber": "449159",
"xM": "fU4B3fR3Dw+UkHNkFsHIjA==",
"gMSFZHM": "qL3GFeI7JO8txKDT25hjuXe5IhnGJ00Jg8+YYbnQ6wg="
},
"photoData": "Qk3OlwAAAAAAADYAAAAoAAAAZgAAAH4AAAABABgAAA..."
}
```
### 参数说明
#### data 对象(必填)
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|--------|------|------|------|--------|
| timeStamp | string | 是 | 毫秒级时间戳与URL参数中的timestamp一致 | `"1713421668375"` |
| customNumber | string | 是 | 自定义编号,使用配置中的 secret_id | `"449159"` |
| xM | string | 是 | 加密后的姓名使用AES加密密钥为配置中的key | `"fU4B3fR3Dw+UkHNkFsHIjA=="` |
| gMSFZHM | string | 是 | 加密后的身份证号使用AES加密密钥为配置中的key | `"qL3GFeI7JO8txKDT25hjuXe5IhnGJ00Jg8+YYbnQ6wg="` |
#### photoData必填
| 参数名 | 类型 | 必填 | 说明 | 示例值 |
|--------|------|------|------|--------|
| photoData | string | 是 | Base64编码的人脸图片数据仅支持JPG、BMP、PNG格式 | `"Qk3OlwAAAAAAADYAAAAoAAAAZgAAAH4AAAABABgAAA..."` |
## 加密说明
### 姓名和身份证号加密
使用 AES-ECB 模式加密,密钥为配置中的 `key`(示例:`121a1e41fc1690dd6b90afbcacd80cf4`
**加密步骤**
1. 使用密钥生成 AES 密钥
2. 使用 AES-ECB 模式加密原始数据
3. 将加密结果进行 Base64 编码
**示例**
- 原始姓名:`"张三"`
- 加密后:`"fU4B3fR3Dw+UkHNkFsHIjA=="`
## 完整请求示例
### cURL 示例
```bash
curl -X POST "https://apimaster.westdex.com.cn/api/invoke/449159/idCardThreeElements?timestamp=1713421668375" \
-H "Content-Type: application/json" \
-d '{
"data": {
"timeStamp": "1713421668375",
"customNumber": "449159",
"xM": "fU4B3fR3Dw+UkHNkFsHIjA==",
"gMSFZHM": "qL3GFeI7JO8txKDT25hjuXe5IhnGJ00Jg8+YYbnQ6wg="
},
"photoData": "Qk3OlwAAAAAAADYAAAAoAAAAZgAAAH4AAAABABgAAA..."
}'
```
### JavaScript 示例
```javascript
const timestamp = Date.now().toString();
const url = `https://apimaster.westdex.com.cn/api/invoke/449159/idCardThreeElements?timestamp=${timestamp}`;
const requestBody = {
data: {
timeStamp: timestamp,
customNumber: "449159",
xM: "fU4B3fR3Dw+UkHNkFsHIjA==", // 加密后的姓名
gMSFZHM: "qL3GFeI7JO8txKDT25hjuXe5IhnGJ00Jg8+YYbnQ6wg=" // 加密后的身份证号
},
photoData: "Qk3OlwAAAAAAADYAAAAoAAAAZgAAAH4AAAABABgAAA..." // Base64图片数据
};
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
})
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error('Error:', error));
```
## 响应格式
### 成功响应
```json
{
"code": "00000",
"message": "成功",
"data": "加密后的响应数据(需要解密)",
"id": "响应ID",
"error_code": null,
"reason": ""
}
```
### 错误响应
```json
{
"code": "错误码",
"message": "错误信息",
"data": "加密后的错误数据(需要解密)",
"id": "响应ID",
"error_code": 错误码,
"reason": "错误原因"
}
```
### 响应状态码说明
| 状态码 | 说明 |
|--------|------|
| `00000` | 成功 |
| `200` | 成功 |
| `0` | 成功 |
| 其他 | 失败 |
## 响应数据解密
响应中的 `data` 字段是加密的,需要使用相同的密钥进行解密:
**解密步骤**
1. 使用配置中的 `key` 作为密钥
2.`data` 字段进行 Base64 解码
3. 使用 AES-ECB 模式解密
4. 得到原始 JSON 字符串
## Apifox 配置步骤
### 1. 创建新请求
- 方法:`POST`
- URL`https://apimaster.westdex.com.cn/api/invoke/449159/idCardThreeElements`
### 2. 设置URL参数
在"Params"标签页添加:
- `timestamp`: `{{$timestamp}}` 使用Apifox变量生成当前时间戳
### 3. 设置请求头
在"Headers"标签页添加:
- `Content-Type`: `application/json`
### 4. 设置请求体
在"Body"标签页选择 `raw` 类型,格式选择 `JSON`,内容如下:
```json
{
"data": {
"timeStamp": "{{$timestamp}}",
"customNumber": "449159",
"xM": "fU4B3fR3Dw+UkHNkFsHIjA==",
"gMSFZHM": "qL3GFeI7JO8txKDT25hjuXe5IhnGJ00Jg8+YYbnQ6wg="
},
"photoData": "Qk3OlwAAAAAAADYAAAAoAAAAZgAAAH4AAAABABgAAA..."
}
```
### 5. 配置环境变量(可选)
在Apifox中创建环境变量
- `westdex_secret_id`: `449159`
- `westdex_key`: `121a1e41fc1690dd6b90afbcacd80cf4`
- `westdex_url`: `https://apimaster.westdex.com.cn/api/invoke`
然后在URL中使用`{{westdex_url}}/{{westdex_secret_id}}/idCardThreeElements?timestamp={{$timestamp}}`
### 6. 前置脚本(用于生成时间戳)
在"前置脚本"中添加:
```javascript
// 生成毫秒级时间戳
pm.environment.set("timestamp", Date.now().toString());
```
然后在URL参数和请求体中使用 `{{timestamp}}`
## 注意事项
1. **时间戳同步**URL参数中的 `timestamp` 和请求体 `data.timeStamp` 必须一致
2. **加密密钥**:姓名和身份证号必须使用配置中的 `key` 进行加密
3. **图片格式**`photoData` 必须是纯Base64字符串不包含 `data:image/xxx;base64,` 前缀)
4. **图片格式限制**:仅支持 JPG、BMP、PNG 三种格式
5. **请求超时**建议设置60秒超时时间
6. **响应解密**:成功响应中的 `data` 字段需要解密后才能查看实际内容
## 配置信息
根据项目配置文件,当前使用的配置为:
- **URL**: `https://apimaster.westdex.com.cn/api/invoke`
- **Key**: `121a1e41fc1690dd6b90afbcacd80cf4`
- **SecretID**: `449159`
- **SecretSecondID**: `296804`
## 测试数据示例
### 原始数据
- 姓名:`张三`
- 身份证号:`110101199001011234`
- 人脸图片需要转换为Base64格式
### 加密后的数据(示例)
- 加密姓名:`fU4B3fR3Dw+UkHNkFsHIjA==`
- 加密身份证号:`qL3GFeI7JO8txKDT25hjuXe5IhnGJ00Jg8+YYbnQ6wg=`
**注意**:实际加密结果会根据密钥和原始数据不同而变化,以上仅为示例格式。

View File

@@ -302,7 +302,7 @@ type IVYZ3A7FReq struct {
type IVYZ9K2LReq struct {
Name string `json:"name" validate:"required,min=1,validName"`
IDCard string `json:"id_card" validate:"required,validIDCard"`
PhotoData string `json:"photo_data" validate:"omitempty,validBase64Image"`
PhotoData string `json:"photo_data" validate:"required,validBase64Image"`
}
type IVYZ9D2EReq struct {

View File

@@ -295,6 +295,8 @@ func (s *FormConfigServiceImpl) parseValidationRules(validateTag string) string
frontendRules = append(frontendRules, "返回链接格式")
case rule == "validAuthorizationURL":
frontendRules = append(frontendRules, "授权链接格式")
case rule == "validBase64Image":
frontendRules = append(frontendRules, "Base64图片格式JPG、BMP、PNG")
case strings.HasPrefix(rule, "oneof="):
values := strings.TrimPrefix(rule, "oneof=")
frontendRules = append(frontendRules, "可选值: "+values)
@@ -324,6 +326,8 @@ func (s *FormConfigServiceImpl) getFieldType(fieldType reflect.Type, validation
return "url"
} else if strings.Contains(validation, "可选值") {
return "select"
} else if strings.Contains(validation, "Base64图片") || strings.Contains(validation, "base64") {
return "textarea"
}
return "text"
case reflect.Int64:
@@ -515,7 +519,7 @@ func (s *FormConfigServiceImpl) generateDescription(jsonTag string, validation s
"plate_type": "号牌类型01-小型汽车02-大型汽车(可选)",
"vin_code": "请输入17位车辆识别代号VIN码Vehicle Identification Number",
"return_type": "返回类型1-专业和学校名称数据返回编码形式默认2-专业和学校名称数据返回中文名称",
"photo_data": "人脸图片(base64编码的图片数据仅支持JPG、BMP、PNG三种格式",
"photo_data": "人脸图片(base64编码的图片数据仅支持JPG、BMP、PNG三种格式",
}
if desc, exists := descMap[jsonTag]; exists {

View File

@@ -10,6 +10,8 @@ import (
"tyapi-server/internal/domains/api/dto"
"tyapi-server/internal/domains/api/services/processors"
"tyapi-server/internal/infrastructure/external/westdex"
"github.com/tidwall/gjson"
)
// ProcessIVYZ9K2LRequest IVYZ9K2L API处理方法 - 身份认证三要素(人脸图像版)
@@ -44,15 +46,13 @@ func ProcessIVYZ9K2LRequest(ctx context.Context, params []byte, deps *processors
// 构建请求数据
reqData := map[string]interface{}{
"timeStamp": timestamp,
"customNumber": customNumber,
"xM": encryptedName,
"gMSFZHM": encryptedIDCard,
}
// 如果提供了人脸图片,添加到请求数据中
if paramsDto.PhotoData != "" {
reqData["photoData"] = paramsDto.PhotoData
"data": map[string]interface{}{
"timeStamp": timestamp,
"customNumber": customNumber,
"xM": encryptedName,
"gMSFZHM": encryptedIDCard,
"photoData": paramsDto.PhotoData,
},
}
respBytes, err := deps.WestDexService.CallAPI(ctx, "idCardThreeElements", reqData)
@@ -67,5 +67,37 @@ func ProcessIVYZ9K2LRequest(ctx context.Context, params []byte, deps *processors
}
}
return respBytes, nil
// 使用gjson提取authResult字段
// 尝试多个可能的路径
var authResult string
paths := []string{
"WEST00037.WEST00038.authResult",
"WEST00036.WEST00037.WEST00038.authResult",
"authResult",
}
for _, path := range paths {
result := gjson.GetBytes(respBytes, path)
if result.Exists() {
authResult = result.String()
break
}
}
// 如果找不到authResult返回ErrDatasource
if authResult == "" {
return nil, errors.Join(processors.ErrDatasource, errors.New("响应中未找到authResult字段"))
}
// 构建返回格式 {result: XXXX}
response := map[string]interface{}{
"result": authResult,
}
responseBytes, err := json.Marshal(response)
if err != nil {
return nil, errors.Join(processors.ErrSystem, err)
}
return responseBytes, nil
}