add ivyz9k2l
This commit is contained in:
261
docs/IVYZ9K2L_WestDex_API文档.md
Normal file
261
docs/IVYZ9K2L_WestDex_API文档.md
Normal 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=`
|
||||
|
||||
**注意**:实际加密结果会根据密钥和原始数据不同而变化,以上仅为示例格式。
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user