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
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"` // 错误信息
|
|
}
|