You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

119 lines
2.7 KiB

// @Time : 2020/7/9 11:14
// @Author : 黑白配
// @File : index
// @PackageName:public
// @Description:
package config
import (
"bytes"
"crypto"
"crypto/rand"
"crypto/rsa"
"crypto/sha256"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"net/http"
"time"
"git.ouxuan.net/3136352472/wxpay/utils"
)
type V3 struct {
MchID string `json:"mchid"` // 商户ID
ClientKeyPath string `json:"clientKeyPath"` // 证书私钥路径
SerialNo string `json:"serialNo"` // 证书编号
}
func (m V3) Request(api string, body interface{}, out interface{}) error {
var request *http.Request
client := http.Client{}
host := "https://api.mch.weixin.qq.com"
if body != nil {
b, _ := json.Marshal(body)
request, _ = http.NewRequest("POST", host+api, bytes.NewReader(b))
} else {
request, _ = http.NewRequest("GET", host+api, nil)
}
sign, err := m.Sign(api, body)
if err != nil {
return err
}
request.Header.Add("Accept", "application/json")
request.Header.Add("Content-Type", "application/json")
request.Header.Add("Authorization", sign)
if resp, err := client.Do(request); err == nil {
defer resp.Body.Close()
b, _ := ioutil.ReadAll(resp.Body)
if len(b) > 0 && out != nil {
return json.Unmarshal(b, out)
} else {
return nil
}
} else {
return err
}
}
// Sign 签名
// @param method string 请求类型
// @param url string 请求地址
// @param body interface 请求数据
func (m V3) Sign(url string, body interface{}) (string, error) {
var data = ""
var method = "GET"
t := time.Now().Unix()
randomStr := utils.RandomStr()
if body != nil {
b, _ := json.Marshal(body)
data = string(b)
method = "POST"
}
str := fmt.Sprintf("%s\n%s\n%d\n%s\n%s\n", method, url, t, randomStr, data)
key, _ := ioutil.ReadFile(m.ClientKeyPath)
sign, err := m.rsaEncrypt([]byte(str), key)
return fmt.Sprintf("WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\","+
"signature=\"%s\",timestamp=\"%d\",serial_no=\"%s\"", m.MchID, randomStr, sign, t, m.SerialNo), err
}
// 私钥加密
func (m V3) rsaEncrypt(data, keyBytes []byte) (string, error) {
//解密pem格式的私钥
block, _ := pem.Decode(keyBytes)
if block == nil {
return "", errors.New("public key error")
}
// 解析私钥
pubInterface, err := x509.ParsePKCS8PrivateKey(block.Bytes)
if err != nil {
return "", err
}
// 类型断言
pub := pubInterface.(*rsa.PrivateKey)
//加密
msg := sha256.Sum256(data)
sign, err := rsa.SignPKCS1v15(rand.Reader, pub, crypto.SHA256, msg[:])
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(sign), nil
}
type Result struct {
Code string `json:"code,omitempty"` // 错误代码
Message string `json:"message,omitempty"` // 错误信息
}