| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399 |
- package asign
- import (
- "encoding/json"
- "mtp20access/global"
- "os/exec"
- "strings"
- "go.uber.org/zap"
- )
- var appId = global.M2A_CONFIG.Asign.AppId
- var privateKey = global.M2A_CONFIG.Asign.PrivateKey
- // 签名规范:
- //
- // 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("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
- }
- // 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"] = appId
- reqData["appKey"] = 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("py", pythonScriptPath)
- // 设置标准输入为JSON字符串
- cmd.Stdin = strings.NewReader(string(reqJSON))
- // 获取标准输出
- output, err := cmd.CombinedOutput()
- if err != nil {
- global.M2A_LOG.Error("[AddPersonalUserBy] 请求失败", zap.Error(err))
- return
- }
- // 结果
- rspBody := string(output)
- 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["signOrder"] = 1 // 1:无序签约(默认
- reqData["templates"] = []map[string]string{
- {"templateNo": templateNo}} // 合同模板编号 - 目前只支持一份合同签一份协议
- reqData["notifyUrl"] = ""
- reqData["api"] = "createContract"
- reqData["appId"] = appId
- reqData["appKey"] = 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("py", pythonScriptPath)
- // 设置标准输入为JSON字符串
- cmd.Stdin = strings.NewReader(string(reqJSON))
- // 获取标准输出
- output, err := cmd.CombinedOutput()
- if err != nil {
- global.M2A_LOG.Error("[AddPersonalUserBy] 请求失败", zap.Error(err))
- return
- }
- // 结果
- rspBody := string(output)
- if err = json.Unmarshal([]byte(rspBody), &rspData); err != nil {
- global.M2A_LOG.Error("[AddPersonalUserBy] 反序列化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["signStrategyList"] = []map[string]int{
- {"attachNo": 1, "locationMode": 4}}
- reqData["api"] = "addSigner"
- reqData["appId"] = appId
- reqData["appKey"] = 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("py", pythonScriptPath)
- // 设置标准输入为JSON字符串
- cmd.Stdin = strings.NewReader(string(reqJSON))
- // 获取标准输出
- output, err := cmd.CombinedOutput()
- if err != nil {
- global.M2A_LOG.Error("[AddSigner] 请求失败", zap.Error(err))
- return
- }
- // 结果
- rspBody := string(output)
- if err = json.Unmarshal([]byte(rspBody), &rspData); err != nil {
- global.M2A_LOG.Error("[AddSigner] 反序列化body失败", zap.Error(err))
- return
- }
- return
- }
|