| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279 |
- package asign
- import (
- "bytes"
- "crypto"
- "crypto/md5"
- "crypto/rsa"
- "crypto/sha256"
- "crypto/x509"
- "encoding/base64"
- "encoding/hex"
- "encoding/json"
- "encoding/pem"
- "errors"
- "fmt"
- "io"
- "mtp20access/global"
- "net/http"
- "net/url"
- "os/exec"
- "strconv"
- "strings"
- "time"
- "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("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
- }
- // addPersonalUser 响应参数
- type AddPersonalUserRsp struct {
- Code int `json:"code"` // 响应码,100000表示成功,其他表示异常
- Msg string `json:"msg"` // 响应信息
- Data AddPersonalUserData `json:"data"` // 响应数据
- }
- 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 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
- }
- // 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 AddPersonalUserRsp, err error) {
- appId := global.M2A_CONFIG.Asign.AppId
- privateKey := global.M2A_CONFIG.Asign.PrivateKey
- 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
- }
|