package pji_client import ( "bytes" "context" "crypto/rand" "crypto/rsa" "crypto/sha256" "crypto/tls" "crypto/x509" "encoding/base64" "encoding/hex" "encoding/json" "encoding/pem" "errors" "fmt" "github.com/cloudwego/hertz/pkg/app/client" "github.com/cloudwego/hertz/pkg/protocol" "io" "mime/multipart" "pji_desktop_http/common/config/c_log" "sort" "strconv" "strings" "time" ) const ( PEM_BEGIN = "-----BEGIN PRIVATE KEY-----\n" PEM_END = "\n-----END PRIVATE KEY-----" ) var ( ApiClient *SysUserApiClient ) var ( //MapSecretId = "bz765sfnx4wsr6axx91b09ugi56jvzqox" // sit MapSecretId = "3vagisc9rpetc2s2154vts5ymybhiz7ie" // 客户环境 //MapPrivateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAJ/7TuC6YrE6wX4qIyKi7ZmGl6cyYkmTwohCsvAnUdTK1l2uX2C4/lVybgFCp4dklZZgNewDDG8jMSp1KxXVUE4TxEJQQt8g1qx0JWPs1GPz5vP67yMndLbGfm360SDLjgnEBYKcpWe65f6eAPjFXgBrwdue2kZBHqTGRB8LwweVAgMBAAECgYABZx67RxHJJA7A9cr2aXSpPU45ym36NIV8KbmP9DL6KV0qgnZA+Yj2uYN6wgQzYmUSuyfojeOfWzD516qCYoB1wJYXXL3OgDP0HLJZ6WsZfIHC4uSfIRtfepccfGDxjWTCoQHYoHMC1uWww79XjqS6bnRgXCulG7itg9SHHfO2cQJBANVuktJq/bZJFGt7tXvV1IAqJ6Cc5zS62OmAeQ7YYJJIdh9xdtW0ASGzVS6Cj5wPfXp/SsfKl9ZGfql3BaeOzhsCQQC/46qqds6ztKfIAs1uKwB7M0SjASXLmO/+4dubvkabbyT4tcSqmAdOt0RqGb7/AgE6QU/an3IdbUcl/RXpLhwPAkBF0CZsd5zHzH3Gbq+9cwNQbPmLWudx4xBiyKhQh8yG7PbecCHb40ZffKaHUSOie5qiwBJ46bbi2ypBSnJqDZczAkBMEjhtXa4yJdNCAoJoQ1nsfXWfXWwbW6UBGY7THkqlghlZE85EhwKWnSbdHRnPxH6yFoROulkl+1VyZPPTvjjXAkEAryJwhKTIYXwc+cgUhWeLY/Yehj6iuwWwOfT9UbuwjnhKgKmn2tPnwY8JJcQQ99zBhQDWizj7Z9F+LlkMR6rlxw==" MapPrivateKey = "MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAIsqA48Nbn1b88SVcwGR1qMXSWCpddHiiMfGcTRAYsWcbCG9y6WFQLVos5XOWI3YjRxxNKe3whQbJk/uxHrie+9cXxE+0LDA87H8MqbT9B13Fe9upW13u2OkL968Q2i2UqQ+BVThByanueZoJTr8jNHZwUDFrp/E+thNwJtM06yrAgMBAAECgYAIiBmyFkw3okCxGh/JW66xeUwrLBMdkXT6Q8Jim4SSrIgn5Ly3QpKY1zjp+RMOayrHhhyIyxK6bH8DooCS2g9n96Kg5R0MkRwAvCoHcdMt68ILGAf0nLdzB5Lefzt6YFI5SK6je3JYtCgc78SQ+qyCuMmEUJ/dWYfNdFSuOYSrwQJBAL9/Iil9+nOOgQ7Ro6Znove0jo0dwjDATZtVMBwRAeSWnGvrBeYflWjSB3b+It2EKaguwDpvG2XWlS9cv53b3msCQQC6CjfXk0bXqj90WCYiqqoInbzMDfZl48WHLXHS3P5/SlKhFAsTIKWyxjOgyRY8ptldBZ6kBazeq4V92WOmtnrBAkEAg2RQ5VVKDhW+GZPgDKJZYEqj8NF1V4vq8+SckPVebiClDSsCLiaHlpddhdjTxVgUWRBS1wU7MEHutMOXulGNJwJAUM8tcGtdo0IlK/E6J2bAUtvJbU1HUPy+CTiZL4Gk3j+3YpZlNRrCPsRPGrEeApxq4DgXr6FzdIlGg+LQoVK0QQJAHQUnrLwftprRcJ1W1xVQqka/EY8/T6Cljh6BPRhLTK6TtXFUSUTcQTeFffW7JH/E4Pz3q3oiEeDI5QlRjCVLjg==" ) func InitApiClient() { var err error c_log.GlobalLogger.Info("初始化Pji Api客户端对象 - 开始。") priv, err := ParsePrivateKey(MapPrivateKey) if err != nil { c_log.GlobalLogger.Error("无法解析私钥:", err) } // 创建客户端 ApiClient, err = NewSysUserApiClient(priv) if err != nil { c_log.GlobalLogger.Error("无法创建 Pji Api客户端:", err) } c_log.GlobalLogger.Info("初始化Pji Api客户端对象 - 成功。") } // SysUserApiClient 是用于API交互的客户端结构体 type SysUserApiClient struct { HttpClient *client.Client // Hertz客户端实例 PrivateKey *rsa.PrivateKey // RSA私钥 } // NewSysUserApiClient 创建并返回一个SysUserApiClient实例 func NewSysUserApiClient(privateKey *rsa.PrivateKey) (*SysUserApiClient, error) { hClient, err := client.NewClient(client.WithTLSConfig(&tls.Config{ InsecureSkipVerify: true, })) if err != nil { return nil, err } return &SysUserApiClient{ HttpClient: hClient, PrivateKey: privateKey, }, nil } func ParsePrivateKey(privateKeyPEM string) (*rsa.PrivateKey, error) { privateKeyPEM = FormatPrivateKey(privateKeyPEM) //fmt.Println("privateKeyPEM", privateKeyPEM) // 解码私钥字节,生成加密对象 block, _ := pem.Decode([]byte(privateKeyPEM)) if block == nil { return nil, errors.New("私钥信息错误!") } //fmt.Println("block", block.Bytes) // 生成私钥对象 priKey, err := x509.ParsePKCS8PrivateKey(block.Bytes) if err != nil { return nil, err } // 类型断言为*RSA私钥 privateKey := priKey.(*rsa.PrivateKey) return privateKey, nil } func FormatPrivateKey(privateKey string) string { if !strings.HasPrefix(privateKey, PEM_BEGIN) { privateKey = PEM_BEGIN + privateKey } if !strings.HasSuffix(privateKey, PEM_END) { privateKey = privateKey + PEM_END } return privateKey } // 辅助函数:对Map的键进行排序 func sortMapByKey(m map[string]interface{}) map[string]interface{} { sortedMap := make(map[string]interface{}) keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { sortedMap[k] = m[k] } return sortedMap } // 生成SHA-256哈希并进行RSA签名 func (c *SysUserApiClient) generateSignature(val string) (string, error) { //fmt.Println("val", val) // 签名摘要 hash := sha256.New() hash.Write([]byte(val)) hashed := hash.Sum(nil) //fmt.Println("hashed", hashed) str := hex.EncodeToString(hashed) bytes1 := []byte(str) //fmt.Println("str", str) //fmt.Println("bytes", bytes) signedData, err := rsa.SignPKCS1v15(rand.Reader, c.PrivateKey, 0, bytes1) str = hex.EncodeToString(signedData) if err != nil { return "", err } //fmt.Println("base64", str) //fmt.Println("base64 signedData", base64.StdEncoding.EncodeToString([]byte(str))) return base64.StdEncoding.EncodeToString([]byte(str)), nil } // 通用请求生成函数,设置通用头部信息 func (c *SysUserApiClient) getHttpRequest(method string, url string, secretId string, encode string) *protocol.Request { req := protocol.AcquireRequest() req.Header.SetMethod(method) req.SetRequestURI(url) req.Header.Set("PJI-TIMESTAMP", strconv.FormatInt(time.Now().Unix(), 10)) req.Header.Set("PJI-API-VERSION", "v1.0") req.Header.Set("PJI-ALGORITHM", "SHA3-256") req.Header.Set("PJI-SECRET-ID", secretId) req.Header.Set("PJI-ABSTRACT-SIGN", encode) return req } // JsonPostRequest 发送带有JSON请求体的POST请求 func (c *SysUserApiClient) JsonPostRequest(url string, paramMap map[string]interface{}, secretId string) (*protocol.Response, error) { paramMap = sortMapByKey(paramMap) jsonData, err := json.Marshal(paramMap) //fmt.Println("jsonData", string(jsonData)) if err != nil { return nil, err } str := string(jsonData) if str == "{}" { return nil, nil } signature, err := c.generateSignature(str) if err != nil { return nil, err } req := c.getHttpRequest("POST", url, secretId, signature) req.SetBody(jsonData) req.Header.Set("Content-Type", "application/json") resp := protocol.AcquireResponse() ctx := context.Background() err = c.HttpClient.Do(ctx, req, resp) return resp, err } // GetRequest 发送GET请求 func (c *SysUserApiClient) GetRequest(url string, paramMap map[string]interface{}, secretId string) (*protocol.Response, error) { paramMap = sortMapByKey(paramMap) jsonData, err := json.Marshal(paramMap) //fmt.Println("jsonData", string(jsonData)) if err != nil { return nil, err } str := string(jsonData) if str == "{}" { str = "" } signature, err := c.generateSignature(str) if err != nil { return nil, err } req := c.getHttpRequest("GET", url, secretId, signature) resp := protocol.AcquireResponse() ctx := context.Background() err = c.HttpClient.Do(ctx, req, resp) return resp, err } // GetRequestWithForm 发送GET请求 func (c *SysUserApiClient) GetRequestWithForm(url string, paramMap map[string]interface{}, secretId string) (*protocol.Response, error) { paramMap = sortMapByKey(paramMap) jsonData, err := json.Marshal(paramMap) fmt.Println("jsonData", string(jsonData)) if err != nil { return nil, err } str := string(jsonData) if str == "{}" { str = "" } signature, err := c.generateSignature(str) if err != nil { return nil, err } newParamMap := make(map[string]string) for k, v := range paramMap { newParamMap[k] = fmt.Sprintf("%v", v) } req := c.getHttpRequest("GET", url, secretId, signature) req.SetHeader("Content-Type", "multipart/form-data") req.SetFormData(newParamMap) resp := protocol.AcquireResponse() ctx := context.Background() err = c.HttpClient.Do(ctx, req, resp) return resp, err } // UploadRequest 上传文件 func (c *SysUserApiClient) UploadRequest(url string, paramMap map[string]interface{}, secretId string, file []byte) (*protocol.Response, error) { paramMap = sortMapByKey(paramMap) jsonData, err := json.Marshal(paramMap) fmt.Println("jsonData", string(jsonData)) if err != nil { return nil, err } str := string(jsonData) if str == "{}" { str = "" } signature, err := c.generateSignature(str) if err != nil { return nil, err } req := c.getHttpRequest("POST", url, secretId, signature) body := &bytes.Buffer{} writer := multipart.NewWriter(body) //req.Header.Set("Content-Type", writer.FormDataContentType()) req.Header.Set("Content-Type", writer.FormDataContentType()) //fmt.Println("req", req.Header.String()) // 添加表单字段 for key, val := range paramMap { part, err := writer.CreateFormField(key) if err != nil { fmt.Println("Error creating form field", key) return nil, err } part.Write([]byte(val.(string))) } formFile, err := writer.CreateFormFile("file", "map.zip") if err != nil { return nil, err } _, err = io.Copy(formFile, bytes.NewReader(file)) //fmt.Println("body", body.String()) writer.Close() req.SetBody(body.Bytes()) // 文件数据可以单独处理 resp := protocol.AcquireResponse() ctx := context.Background() err = c.HttpClient.Do(ctx, req, resp) return resp, err } // 辅助函数:对字符串Map的键进行排序 func sortMapByKeyString(m map[string]string) map[string]string { sortedMap := make(map[string]string) keys := make([]string, 0, len(m)) for k := range m { keys = append(keys, k) } sort.Strings(keys) for _, k := range keys { sortedMap[k] = m[k] } return sortedMap }