package asign import ( "bytes" "encoding/json" "mtp20access/global" "os/exec" "strings" "go.uber.org/zap" ) // 签名规范: // // 1、表单提交方式:form-data // 2、请求头部参数 // 参数1:sign(签名值,具体算法参考一下的前面算法) // 参数2:timestamp(时间戳,13位) // 3、请求体参数: // 参数1:appId(appId值,每个接入者唯一一个) // 参数2:timestamp(时间戳,13位,与上述一致) // 参数3:bizData(json字符串,举个例子,比方说要传合同编号如:{"contractNo":"0001"}) // 4、签名算法: // 4.1、将上述3所属的bizData(json字符串),按照阿拉伯字母排序(如:{"ba":1,"ac":2}--->{"ac":2,"ba":1}), // 4.2、将4.1排序后的字符串,将【bizData+md5(bizData)+ appId + timestatmp】拼接后利用RSA非对称加密算法(SHA1withRSA),计算出最后的签名sign,对其base64编码,放入head的key(sign)中。 // func getSignature(bizData string, appId string, privateKeyPEM string) (signatureBase64 string, timestamp string, err error) { // timestamp = strconv.FormatInt(time.Now().UnixMilli(), 10) // privateKeyBlock, _ := pem.Decode([]byte(privateKeyPEM)) // // if privateKeyBlock == nil || privateKeyBlock.Type != "RSA PRIVATE KEY" { // if privateKeyBlock == nil { // err = errors.New("签名失败: Error decoding private key PEM") // return // } // // 解析 PKCS#8 格式的私钥 // privateKey, err := x509.ParsePKCS1PrivateKey(privateKeyBlock.Bytes) // if err != nil { // fmt.Println("Failed to parse private key:", err) // return // } // // md5(bizData) // m := md5.New() // m.Write([]byte(bizData)) // bdMd5Hx := hex.EncodeToString(m.Sum(nil)) // // 待签内容 // message := bizData + bdMd5Hx + appId + timestamp // // 使用私钥进行签名 // hashed := sha256.Sum256([]byte(message)) // signature, err := rsa.SignPKCS1v15(nil, privateKey, crypto.SHA256, hashed[:]) // if err != nil { // fmt.Println("Error signing:", err) // return // } // // fmt.Println(signature) // signatureBase64 = base64.StdEncoding.EncodeToString(signature) // return // } // type pySignReqData struct { // ReqBodyData string `json:"reqBodyData"` // Timestamp string `json:"timestamp"` // AppId string `json:"appId"` // AppKey string `json:"appKey"` // } // func getSignatureByPy(bizData string, appId string, privateKeyPEM string) (signatureBase64 string, timestamp string, err error) { // // md5(bizData) // m := md5.New() // m.Write([]byte(bizData)) // bdMd5Hx := hex.EncodeToString(m.Sum(nil)) // timestamp = strconv.FormatInt(time.Now().UnixMilli(), 10) // // timestamp = "1691559290641" // // 待签内容 // message := bizData + bdMd5Hx + appId + timestamp // // 构建请求数据结构 // reqData := pySignReqData{ // ReqBodyData: message, // Timestamp: timestamp, // AppId: appId, // AppKey: privateKeyPEM, // } // // 将请求数据转换为JSON字符串 // reqJSON, err := json.Marshal(reqData) // if err != nil { // global.M2A_LOG.Error("[getSignatureByPy] 构建请求参数失败", zap.Error(err)) // return // } // // 要执行的Python脚本命令 // pythonScriptPath := "./py/sign.py" // // 创建一个命令对象 // cmd := exec.Command(global.M2A_CONFIG.Asign.Py, pythonScriptPath) // // 设置标准输入为JSON字符串 // cmd.Stdin = strings.NewReader(string(reqJSON)) // // 获取标准输出 // output, err := cmd.CombinedOutput() // if err != nil { // global.M2A_LOG.Error("[getSignatureByPy] 签名失败", zap.Error(err)) // return // } // // 获取签名结果 // signatureBase64 = string(output) // return // } type AsignData interface { AddPersonalUserData | CreateContractData | AddSignerData | DownloadContractData | ContractStatusData | WillFaceData } // AsignRsp 爱签响应参数 type AsignRsp[T AsignData] struct { Code int `json:"code"` // 响应码,100000表示成功,其他表示异常 Msg string `json:"msg"` // 响应信息 Data T `json:"data"` // 响应数据 } // https://preweb.asign.cn/platform/openDoc/docDetail?mid=addPersonalUser // 添加个人用户(https://{host}/user/addPersonalUser) // 错误码 错误描述 // 100021 用户已存在 // 100156 手机号码格式错误 // 100157 邮箱格式错误 // 100571 参数错误,唯一识别码Account为空 // 100577 参数错误,{param}长度超过限制:{length} // 100579 参数错误,{param}不能为空 // 100598 参数错误,身份证号码格式不正确 // 100639 参数错误,名字点号格式不正确 // func AddPersonalUser(account, name, idCard, mobile string, idCardType *int) (rspData AddPersonalUserRsp, err error) { // apiUrl := global.M2A_CONFIG.Asign.URL + "user/addPersonalUser" // appId := "290912417" // privateKey := `MIIBUwIBADANBgkqhkiG9w0BAQEFAASCAT0wggE5AgEAAkEAkMD+72J6iAF0ZNV+3t628lsRHfJ80nKZWK5/C7Pg+AZmOIzJlwHsKhRzCvxoxqYHQprhiFzW9l73v9vD9l1JYwIDAQABAkBVijccr01JYdKuY5t9iI8D2NzcnZc1pZMI3NUmzT18Uyg7b9CUvGHlLeg/gdT4QtVd7wIzHYCY4letEcEMh54BAiEAwzNWusj5XiLmty7PI0Hbakx4HtcND1+P0UHLEWqWOuECIQC91zQuL7nStgGzT3HvaeBB5Ouapa39fHRm2nCjHaxwwwIgRR2XdvmUOj23XWMomr5F14SN/7V7fVcD0D8wjNElsmECIDYavV5kb7tj7/wgqkInlKhzC8rZaUsTS0F9BBkY/eptAiAQJ8Saz8YlMIESdHMxANGSog01fECbcZqLFMuNf8SorA==` // // 请求参数 // params := make(map[string]interface{}) // params["account"] = account // params["name"] = name // params["idCard"] = idCard // params["idCardType"] = 1 // if idCardType != nil { // params["idCardType"] = *idCardType // } // params["mobile"] = mobile // // 用户实名认证模式为强制认证时,需要选择认证方法: // // 1:身份证二要素认证 // // 2:运营商三要素认证 // // 3:银行卡四要素认证 // params["identifyType"] = 2 // params["identifyMobile"] = mobile // params["isNotice"] = 1 // bizData, err := json.Marshal(params) // if err != nil { // global.M2A_LOG.Error("[AddPersonalUser] 构建请求参数失败", zap.Error(err)) // return // } // global.M2A_LOG.Info("[AddPersonalUser] 构建请求参数", zap.Any("params", string(bizData))) // // 签名 // sign, timestamp, err := getSignatureByPy(string(bizData), appId, privateKey) // sign = strings.Replace(sign, "\r\n", "", -1) // sign = strings.Replace(sign, "\r", "", -1) // if err != nil { // global.M2A_LOG.Error("[AddPersonalUser] 签名失败", zap.Error(err)) // return // } // global.M2A_LOG.Info("[AddPersonalUser] 签名", zap.Any("sign", sign)) // // 构建form-data请求参数 // formValues := url.Values{} // formValues.Set("appId", appId) // formValues.Set("timestamp", timestamp) // formValues.Set("bizData", string(bizData)) // // 构建请求 // req, err := http.NewRequest("POST", apiUrl, bytes.NewReader([]byte(formValues.Encode()))) // // 设置请求头 // req.Header.Set("sign", sign) // req.Header.Set("timestamp", timestamp) // req.Header.Set("Content-Type", "multipart/form-data; charset=UTF-8") // req.Header.Set("Accept", "*/*") // client := &http.Client{} // rsp, err := client.Do(req) // if err != nil { // global.M2A_LOG.Error("[AddPersonalUser] 请求失败", zap.Error(err)) // return // } // defer rsp.Body.Close() // body, err := io.ReadAll(rsp.Body) // if err != nil { // global.M2A_LOG.Error("[AddPersonalUser] 获取body失败", zap.Error(err)) // return // } // if err = json.Unmarshal(body, &rspData); err != nil { // global.M2A_LOG.Error("[AddPersonalUser] 反序列化body失败", zap.Error(err)) // return // } // return // } type AddPersonalUserData struct { SealNo string `json:"sealNo"` // 默认印章编号 } // https://preweb.asign.cn/platform/openDoc/docDetail?mid=addPersonalUser // 添加个人用户(https://{host}/user/addPersonalUser) // 错误码 错误描述 // 100021 用户已存在 // 100156 手机号码格式错误 // 100157 邮箱格式错误 // 100571 参数错误,唯一识别码Account为空 // 100577 参数错误,{param}长度超过限制:{length} // 100579 参数错误,{param}不能为空 // 100598 参数错误,身份证号码格式不正确 // 100639 参数错误,名字点号格式不正确 func AddPersonalUserBy(account, name, idCard, mobile string, idCardType *int) (rspData AsignRsp[AddPersonalUserData], err error) { apiUrl := global.M2A_CONFIG.Asign.URL + "user/addPersonalUser" // 构建请求数据结构 reqData := make(map[string]interface{}) reqData["account"] = account reqData["name"] = name reqData["mobile"] = mobile reqData["idCard"] = idCard reqData["idCardType"] = 1 if idCardType != nil { reqData["idCardType"] = *idCardType } reqData["api"] = "addPerson" reqData["appId"] = global.M2A_CONFIG.Asign.AppId reqData["appKey"] = global.M2A_CONFIG.Asign.PrivateKey reqData["apiUrl"] = apiUrl // 将请求数据转换为JSON字符串 reqJSON, err := json.Marshal(reqData) if err != nil { global.M2A_LOG.Error("[AddPersonalUserBy] 构建请求参数失败", zap.Error(err)) return } // 要执行的Python脚本命令 pythonScriptPath := "./py/Enter.py" // 创建一个命令对象 cmd := exec.Command(global.M2A_CONFIG.Asign.Py, pythonScriptPath) // 设置标准输入为JSON字符串 cmd.Stdin = strings.NewReader(string(reqJSON)) // 创建一个字节缓冲区来捕获命令的输出 var stdoutBuf, stderrBuf bytes.Buffer cmd.Stdout = &stdoutBuf cmd.Stderr = &stderrBuf // 执行命令 err = cmd.Run() // 输出标准输出和标准错误 global.M2A_LOG.Info("AddPersonalUserBy 标准输出:", zap.Any("stdoutBuf", stdoutBuf.String())) global.M2A_LOG.Info("AddPersonalUserBy 标准错误:", zap.Any("stderrBuf", stderrBuf.String())) if err != nil { global.M2A_LOG.Error("[AddPersonalUserBy] 请求失败", zap.Error(err)) return } // 结果 rspBody := stdoutBuf.String() // 正确返回 // {"code":100000,"msg":"�ɹ�","data":{"id":null,"userId":null,"partnerId":null,"type":null,"sealType":null,"sealTypeOfUser":null,"sealName":null,"sealCode":null,"startTime":null,"endTime":null,"sealNo":"9a82d2da479b4430b1da6f7f7cd96aee","sealPassword":null,"sealFont":null,"version":null,"caType":null,"certNo":null,"path":null,"isDefault":null,"status":null,"color":null,"fontSize":null,"imageWidth":null,"imageHeight":null,"imageShape":null,"signTimes":null,"logicDel":null,"createTime":null,"modifyTime":null}} // 错误返回 // {"code":100021,"msg":"�û��Ѵ��ڣ�����֤�����ظ�","data":{"id":null,"partnerId":null,"account":"100000007","companyAccount":null,"name":null,"companyName":null,"userType":null,"mobile":null,"bankCard":null,"email":null,"idCard":"360428200007287603","idCardType":null,"creditCode":null,"contactName":null,"contactPhone":null,"contactIdCard":null,"isNotice":null,"isAutoSign":null,"signPwd":null,"identifyStatus":null,"identifyMobile":null,"identifyType":null,"userStatus":null,"needSeal":null,"remark":null,"createTime":null,"modifyTime":null,"sealType":null,"authType":null,"serialNo":null}} if err = json.Unmarshal([]byte(rspBody), &rspData); err != nil { global.M2A_LOG.Error("[AddPersonalUserBy] 反序列化body失败", zap.Error(err)) return } return } type CreateContractData struct { PreviewUrl string `json:"previewUrl"` // 合同预览链接 ContractFiles []interface{} `json:"contractFiles"` // 合同文件信息(文件名称,附件编号,页数) } /* * CreateContract 上传待签署文件 contractNo 合同ID,合同唯一编号 contractName 合同名称 templateNo 合同模板编号 * */ func CreateContract(contractNo, contractName, templateNo string) (rspData AsignRsp[CreateContractData], err error) { apiUrl := global.M2A_CONFIG.Asign.URL + "contract/createContract" // 构建请求数据结构 reqData := make(map[string]interface{}) reqData["contractNo"] = contractNo reqData["contractName"] = contractName reqData["validityTime"] = 30 reqData["signOrder"] = 1 // 1:无序签约(默认 reqData["templates"] = []map[string]string{ {"templateNo": templateNo}} // 合同模板编号 - 目前只支持一份合同签一份协议 reqData["notifyUrl"] = global.M2A_CONFIG.Asign.NotifyUrl reqData["api"] = "createContract" reqData["appId"] = global.M2A_CONFIG.Asign.AppId reqData["appKey"] = global.M2A_CONFIG.Asign.PrivateKey reqData["apiUrl"] = apiUrl // 将请求数据转换为JSON字符串 reqJSON, err := json.Marshal(reqData) if err != nil { global.M2A_LOG.Error("[CreateContract] 构建请求参数失败", zap.Error(err)) return } // 要执行的Python脚本命令 pythonScriptPath := "./py/Enter.py" // 创建一个命令对象 cmd := exec.Command(global.M2A_CONFIG.Asign.Py, pythonScriptPath) // 设置标准输入为JSON字符串 cmd.Stdin = strings.NewReader(string(reqJSON)) // 创建一个字节缓冲区来捕获命令的输出 var stdoutBuf, stderrBuf bytes.Buffer cmd.Stdout = &stdoutBuf cmd.Stderr = &stderrBuf // 执行命令 err = cmd.Run() // 输出标准输出和标准错误 // fmt.Println("标准输入:", string(reqJSON)) global.M2A_LOG.Info("CreateContract 标准输出:", zap.Any("stdoutBuf", stdoutBuf.String())) global.M2A_LOG.Info("CreateContract 标准错误:", zap.Any("stderrBuf", stderrBuf.String())) if err != nil { global.M2A_LOG.Error("[CreateContract] 请求失败", zap.Error(err)) return } // 结果 rspBody := stdoutBuf.String() // 正确返回:CreateContract 标准输出: {"code":100000,"msg":" ɹ ","data":{"pageSizeMap":{},"signUser":[],"previewUrl":"https://pre.asign.cn/m/#/mobile/previewApiContract/QhUqHj669cOmXIPrJ7eOhSfWh6_oDGlmQ53lOD5OVAvJRvTVpenYICiMWnvbCi4swvNWUIVuO1zPsTvIvHPGuE1fTZ-AQyCeUyWWu7f56Jg?expired=10800000","contractFiles":[]}} if err = json.Unmarshal([]byte(rspBody), &rspData); err != nil { global.M2A_LOG.Error("[CreateContract] 反序列化body失败", zap.Error(err)) return } return } // 合同用户信息 type SignUserData struct { Account string `json:"account"` // 用户唯一识别码 SignUrl string `json:"signUrl"` // 合同签署链接 PwdSignUrl string `json:"pwdSignUrl"` // 密码签署链接 SignOrder int `json:"signOrder"` // 顺序签约的序号 Name string `json:"name"` // 用户姓名 IdCard string `json:"idCard"` // 用户身份证 } // 添加签署方响应数据 type AddSignerData struct { ContractNo string `json:"contractNo"` // 合同编号 ContractName string `json:"contractName"` // 合同名称 ValidityTime string `json:"validityTime"` // 合同有效期 PreviewUrl string `json:"previewUrl"` // 合同预览链接 SignUser []SignUserData `json:"signUser"` // 合同用户信息 } /* * AddSigner 添加签署方 contractNo 合同ID,合同唯一编号 account 用户唯一识别码(UserID) * */ func AddSigner(contractNo, account string) (rspData AsignRsp[AddSignerData], err error) { apiUrl := global.M2A_CONFIG.Asign.URL + "contract/addSigner" // 构建请求数据结构 reqData := make(map[string]interface{}) reqData["contractNo"] = contractNo reqData["account"] = account reqData["signType"] = 3 // 签署方式指定:(从以下分类中指定一种) // 1:短信验证码签约(支持企业和个人) // 2:签约密码签约(支持企业和个人) // 3:人脸识别签约(支持企业和个人) // 4:手写签名(不推荐,仅限个人) // 6:手写识别签名+短信签约(仅限个人) // 7:手写签名+短信签约(仅限个人) // 8:手写签名+人脸识别签约(仅限个人) // 9:手写识别签名+人脸识别签约(仅限个人) reqData["validateType"] = 4 reqData["signStrategyList"] = []map[string]interface{}{ {"attachNo": 1, "locationMode": 4, "signKey": "key_sign_name"}, {"attachNo": 1, "locationMode": 4, "signKey": "key_sign_date"}, } reqData["api"] = "addSigner" reqData["appId"] = global.M2A_CONFIG.Asign.AppId reqData["appKey"] = global.M2A_CONFIG.Asign.PrivateKey reqData["apiUrl"] = apiUrl // 将请求数据转换为JSON字符串 reqJSON, err := json.Marshal(reqData) if err != nil { global.M2A_LOG.Error("[AddSigner] 构建请求参数失败", zap.Error(err)) return } // 要执行的Python脚本命令 pythonScriptPath := "./py/Enter.py" // 创建一个命令对象 cmd := exec.Command(global.M2A_CONFIG.Asign.Py, pythonScriptPath) // 设置标准输入为JSON字符串 cmd.Stdin = strings.NewReader(string(reqJSON)) // 创建一个字节缓冲区来捕获命令的输出 var stdoutBuf, stderrBuf bytes.Buffer cmd.Stdout = &stdoutBuf cmd.Stderr = &stderrBuf // 执行命令 err = cmd.Run() // 输出标准输出和标准错误 global.M2A_LOG.Info("AddSigner 标准输出:", zap.Any("stdoutBuf", stdoutBuf.String())) global.M2A_LOG.Info("AddSigner 标准错误:", zap.Any("stderrBuf", stderrBuf.String())) if err != nil { global.M2A_LOG.Error("[AddSigner] 请求失败", zap.Error(err)) return } // 结果 // 正确返回:AddSigner 标准输出: {"code":100000,"msg":"�ɹ�","data":{"contractNo":"100000008_20230815145538_10","pageSizeMap":{},"contractName":"���ݲ�Ҷ������ʾ�飨10.31���հ棩","signOrder":1,"validityTime":"2023-09-14","signUser":[{"account":"100000008","signUrl":"https://h5.asign.cn/web/short/eE7zmq515512","signOrder":1,"name":"����̼��","idCard":"110101200007285605","mobile":"15914012153"}],"previewUrl":"https://pre.asign.cn/m/#/mobile/previewApiContract/QhUqHj669cOmXIPrJ7eOhSfWh6_oDGlmQ53lOD5OVAvJRvTVpenYICiMWnvbCi4sS_knh8JQ124Lwf_uxqXkF0-n1uuC18qLy5B8TfAF88g?expired=10800000","contractFiles":[]}} // 错误返回:AddSigner 标准输出: {"code":100617,"msg":"ģ IJ [key_sign_name] ","data":null} rspBody := stdoutBuf.String() if err = json.Unmarshal([]byte(rspBody), &rspData); err != nil { global.M2A_LOG.Error("[AddSigner] 反序列化body失败", zap.Error(err)) return } return } // 下载合同响应数据 type DownloadContractData struct { FileName string `json:"fileName"` // 文件名 MD5 string `json:"md5"` // 文件md5值 FileType int `json:"fileType"` // 文件类型 0:PDF 1:ZIP Size int `json:"size"` // 文件大小 Data string `json:"data"` // Base64字符串 } /* DownloadContract 下载合同 contractNo 合同ID,合同唯一编号 */ func DownloadContract(contractNo string) (rspData AsignRsp[DownloadContractData], err error) { apiUrl := global.M2A_CONFIG.Asign.URL + "contract/downloadContract" // 构建请求数据结构 reqData := make(map[string]interface{}) reqData["contractNo"] = contractNo reqData["api"] = "downloadContract" reqData["appId"] = global.M2A_CONFIG.Asign.AppId reqData["appKey"] = global.M2A_CONFIG.Asign.PrivateKey reqData["apiUrl"] = apiUrl // 将请求数据转换为JSON字符串 reqJSON, err := json.Marshal(reqData) if err != nil { global.M2A_LOG.Error("[DownloadContract] 构建请求参数失败", zap.Error(err)) return } // 要执行的Python脚本命令 pythonScriptPath := "./py/Enter.py" // 创建一个命令对象 cmd := exec.Command(global.M2A_CONFIG.Asign.Py, pythonScriptPath) // 设置标准输入为JSON字符串 cmd.Stdin = strings.NewReader(string(reqJSON)) // 创建一个字节缓冲区来捕获命令的输出 var stdoutBuf, stderrBuf bytes.Buffer cmd.Stdout = &stdoutBuf cmd.Stderr = &stderrBuf // 执行命令 err = cmd.Run() // 输出标准输出和标准错误 global.M2A_LOG.Info("DownloadContract 标准输出:", zap.Any("stdoutBuf", stdoutBuf.String())) global.M2A_LOG.Info("DownloadContract 标准错误:", zap.Any("stderrBuf", stderrBuf.String())) if err != nil { global.M2A_LOG.Error("[DownloadContract] 请求失败", zap.Error(err)) return } // 结果 rspBody := stdoutBuf.String() if err = json.Unmarshal([]byte(rspBody), &rspData); err != nil { global.M2A_LOG.Error("[DownloadContract] 反序列化body失败", zap.Error(err)) return } return } // 查询合同状态响应数据 type ContractStatusData struct { ContractNo string `json:"contractNo"` // 合同唯一编号 ContractName string `json:"contractName"` // 合同名称 Status int `json:"status"` // 合同状态:0:等待签约 1:签约中 2:已签约 3:过期 4:拒签 6:作废 -2:状态异常 } /* ContractStatus 查询合同状态 contractNo 合同ID,合同唯一编号 */ func ContractStatus(contractNo string) (rspData AsignRsp[ContractStatusData], err error) { apiUrl := global.M2A_CONFIG.Asign.URL + "contract/status" // 构建请求数据结构 reqData := make(map[string]interface{}) reqData["contractNo"] = contractNo reqData["api"] = "contractStatus" reqData["appId"] = global.M2A_CONFIG.Asign.AppId reqData["appKey"] = global.M2A_CONFIG.Asign.PrivateKey reqData["apiUrl"] = apiUrl // 将请求数据转换为JSON字符串 reqJSON, err := json.Marshal(reqData) if err != nil { global.M2A_LOG.Error("[ContractStatus] 构建请求参数失败", zap.Error(err)) return } // 要执行的Python脚本命令 pythonScriptPath := "./py/Enter.py" // 创建一个命令对象 cmd := exec.Command(global.M2A_CONFIG.Asign.Py, pythonScriptPath) // 设置标准输入为JSON字符串 cmd.Stdin = strings.NewReader(string(reqJSON)) // 创建一个字节缓冲区来捕获命令的输出 var stdoutBuf, stderrBuf bytes.Buffer cmd.Stdout = &stdoutBuf cmd.Stderr = &stderrBuf // 执行命令 err = cmd.Run() // 输出标准输出和标准错误 global.M2A_LOG.Info("ContractStatus 标准输出:", zap.Any("stdoutBuf", stdoutBuf.String())) global.M2A_LOG.Info("ContractStatus 标准错误:", zap.Any("stderrBuf", stderrBuf.String())) if err != nil { global.M2A_LOG.Error("[ContractStatus] 请求失败", zap.Error(err)) return } // 结果 rspBody := stdoutBuf.String() if err = json.Unmarshal([]byte(rspBody), &rspData); err != nil { global.M2A_LOG.Error("[ContractStatus] 反序列化body失败", zap.Error(err)) return } return } // 个人意愿核身认证响应数据 type WillFaceData struct { Result int `json:"result"` // 认证结果:0.暂无结果/认证中 SerialNo string `json:"serialNo"` // 认证流水号 Type string `json:"type"` // 认证类型 FaceUrl string `json:"faceUrl"` // 意愿核身链接 } /* WillFace 个人意愿核身认证 */ func WillFace(realName, idCardNo, question, answer, recordId string) (rspData AsignRsp[WillFaceData], err error) { apiUrl := global.M2A_CONFIG.Asign.URL + "auth/person/willFace" // 构建请求数据结构 reqData := make(map[string]interface{}) reqData["realName"] = realName reqData["idCardNo"] = idCardNo reqData["question"] = question reqData["answer"] = answer reqData["redirectUrl"] = global.M2A_CONFIG.Asign.WillFaceRedirectUrl + "?recordId=" + recordId reqData["api"] = "willFace" reqData["appId"] = global.M2A_CONFIG.Asign.AppId reqData["appKey"] = global.M2A_CONFIG.Asign.PrivateKey reqData["apiUrl"] = apiUrl // 将请求数据转换为JSON字符串 reqJSON, err := json.Marshal(reqData) if err != nil { global.M2A_LOG.Error("[WillFace] 构建请求参数失败", zap.Error(err)) return } // 要执行的Python脚本命令 pythonScriptPath := "./py/Enter.py" // 创建一个命令对象 cmd := exec.Command(global.M2A_CONFIG.Asign.Py, pythonScriptPath) // 设置标准输入为JSON字符串 cmd.Stdin = strings.NewReader(string(reqJSON)) // 创建一个字节缓冲区来捕获命令的输出 var stdoutBuf, stderrBuf bytes.Buffer cmd.Stdout = &stdoutBuf cmd.Stderr = &stderrBuf // 执行命令 err = cmd.Run() // 输出标准输出和标准错误 global.M2A_LOG.Info("WillFace 标准输出:", zap.Any("stdoutBuf", stdoutBuf.String())) global.M2A_LOG.Info("WillFace 标准错误:", zap.Any("stderrBuf", stderrBuf.String())) if err != nil { global.M2A_LOG.Error("[WillFace] 请求失败", zap.Error(err)) return } // 结果 rspBody := stdoutBuf.String() if err = json.Unmarshal([]byte(rspBody), &rspData); err != nil { global.M2A_LOG.Error("[WillFace] 反序列化body失败", zap.Error(err)) return } return }