| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- package server
- import (
- "crypto"
- "crypto/rand"
- "crypto/rsa"
- "crypto/x509"
- "encoding/base64"
- "encoding/json"
- "encoding/pem"
- "errors"
- "fmt"
- "github.com/shopspring/decimal"
- "github.com/spf13/viper"
- "go_zh/pkg/http"
- "go_zh/pkg/utils"
- "net/url"
- "os"
- "sync"
- "time"
- )
- type WeChatServer struct {
- MchId string //微信支付商户号
- PrivateKey string //微信支付私钥
- CertFile string //公钥证书地址
- KeyFile string //私钥证书地址
- AppId string //公众号id
- AppSecret string //公众号密钥
- AppletId string //小程序appid
- AppletKey string //小程序密钥
- CertificateSerialNo string //商户API证书序列号
- WechatPayPublicKeyId string //微信支付公钥ID
- privateKeyInfo *rsa.PrivateKey
- wechatPayPublicKeyInfo *rsa.PublicKey
- }
- // 小程序登录信息返回结构体
- type AppletsOpenData struct {
- ErrorMsg string `json:"errmsg"`
- ErrorCode int `json:"errcode"`
- UnionId string `json:"unionid"`
- SessionKey string `json:"session_key"`
- Openid string `json:"openid"`
- }
- var (
- weChatServerInstance *WeChatServer
- weChatServerOnce sync.Once
- )
- // GetWeChatServerInstance 获取单例实例
- func GetWeChatServerInstance() *WeChatServer {
- weChatServerOnce.Do(func() {
- weChatServerInstance = &WeChatServer{
- MchId: viper.GetString("weChat.mchId"),
- PrivateKey: viper.GetString("weChat.privateKey"),
- CertFile: viper.GetString("weChat.certFile"),
- KeyFile: viper.GetString("weChat.keyFile"),
- AppId: viper.GetString("weChat.appId"),
- AppSecret: viper.GetString("weChat.appSecret"),
- AppletId: viper.GetString("weChat.appletId"),
- AppletKey: viper.GetString("weChat.appletKey"),
- CertificateSerialNo: viper.GetString("weChat.certificateSerialNo"),
- WechatPayPublicKeyId: viper.GetString("weChat.wechatPayPublicKeyId"),
- }
- privateKey, _ := LoadPrivateKeyWithPath(weChatServerInstance.KeyFile)
- weChatServerInstance.privateKeyInfo = privateKey
- wechatPayPublicKey, _ := LoadPublicKeyWithPath(weChatServerInstance.CertFile)
- weChatServerInstance.wechatPayPublicKeyInfo = wechatPayPublicKey
- })
- return weChatServerInstance
- }
- // JsapiPrepayResponse 微信支付jsapi 返回信息结构体
- type JsapiPrepayResponse struct {
- PrepayId string `json:"prepay_id,omitempty"`
- }
- // GetAppletsOpenId 微信小程序获取登录openId
- func (wx *WeChatServer) GetAppletsOpenId(code string) (AppletsOpenData, error) {
- curlUrl := "https://api.weixin.qq.com/sns/jscode2session"
- //发起http get请求
- var appletsOpenRes AppletsOpenData
- requestData := http.RequestData{}
- err := requestData.ConstructRequest(curlUrl)
- if err != nil {
- return appletsOpenRes, err
- }
- requestData.SetData("grant_type", "authorization_code")
- requestData.SetData("appid", wx.AppletId)
- requestData.SetData("secret", wx.AppletKey)
- requestData.SetData("js_code", code)
- ret, err := requestData.GetRequest()
- _ = json.Unmarshal(ret, &appletsOpenRes)
- return appletsOpenRes, nil
- }
- // WeChatJsPay 微信公众号jsapi支付信息
- func (wx *WeChatServer) WeChatJsPay(orderSn string, payMoney decimal.Decimal, notifyUrl string, boby string, wxOpenid string) {
- curlUrl := "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"
- result := make(map[string]interface{})
- amount := make(map[string]interface{})
- amount["total"] = payMoney.Mul(decimal.NewFromInt(100)).IntPart()
- amount["currency"] = "CNY"
- payer := make(map[string]interface{})
- payer["openid"] = wxOpenid
- result["appid"] = wx.AppId
- result["mchid"] = wx.MchId
- result["description"] = boby
- result["out_trade_no"] = orderSn
- result["notify_url"] = notifyUrl
- result["amount"] = amount
- result["payer"] = payer
- body, _ := json.Marshal(result)
- fmt.Println("请求信息:", string(body))
- res, _ := wx.JsapiPrepay(curlUrl, orderSn, body)
- fmt.Println(res)
- }
- func (wx *WeChatServer) JsapiPrepay(curlUrl string, orderSn string, body []byte) (JsapiPrepayResponse, error) {
- //定义返回信息
- var jsapiPrepayResponse JsapiPrepayResponse
- //解析请求url,主要用于加密请求头信息
- reqUrl, err := url.Parse(curlUrl)
- if err != nil {
- return jsapiPrepayResponse, err
- }
- //初始化请求
- requestData := http.RequestData{}
- err = requestData.ConstructRequest(curlUrl)
- if err != nil {
- return jsapiPrepayResponse, err
- }
- requestData.DataByte = body //请求json信息
- //组装请求头
- requestData.SetHeader("Accept", "application/json")
- var authorization string
- authorization, err = buildAuthorization(wx.MchId, orderSn, wx.CertificateSerialNo, wx.privateKeyInfo, "POST", reqUrl.RequestURI(), body)
- requestData.SetHeader("Authorization", authorization)
- var ret []byte
- ret, err = requestData.PostJsonRequest()
- if err != nil {
- return jsapiPrepayResponse, err
- }
- fmt.Println(string(ret))
- return jsapiPrepayResponse, nil
- }
- // buildAuthorization 构建请求头中的 Authorization 信息
- func buildAuthorization(
- mchid string,
- orderSn string,
- certificateSerialNo string,
- privateKey *rsa.PrivateKey,
- method string,
- canonicalURL string,
- body []byte,
- ) (string, error) {
- const (
- SignatureMessageFormat = "%s\n%s\n%d\n%s\n%s\n" // 数字签名原文格式
- // HeaderAuthorizationFormat 请求头中的 Authorization 拼接格式
- HeaderAuthorizationFormat = "WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\""
- )
- nonce := utils.Md5Sign(orderSn) //随机字符串
- timestamp := time.Now().Unix() //输出当前Unix时间戳
- message := fmt.Sprintf(SignatureMessageFormat, method, canonicalURL, timestamp, nonce, body)
- signature, err := SignSHA256WithRSA(message, privateKey)
- if err != nil {
- return "", err
- }
- authorization := fmt.Sprintf(
- HeaderAuthorizationFormat,
- mchid, nonce, timestamp, certificateSerialNo, signature,
- )
- return authorization, nil
- }
- // LoadPrivateKey 通过私钥的文本内容加载私钥
- func LoadPrivateKey(privateKeyStr string) (privateKey *rsa.PrivateKey, err error) {
- block, _ := pem.Decode([]byte(privateKeyStr))
- if block == nil {
- return nil, fmt.Errorf("decode private key err")
- }
- if block.Type != "PRIVATE KEY" {
- return nil, fmt.Errorf("the kind of PEM should be PRVATE KEY")
- }
- key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
- if err != nil {
- return nil, fmt.Errorf("parse private key err:%s", err.Error())
- }
- privateKey, ok := key.(*rsa.PrivateKey)
- if !ok {
- return nil, fmt.Errorf("not a RSA private key")
- }
- return privateKey, nil
- }
- // LoadPublicKey 通过公钥的文本内容加载公钥
- func LoadPublicKey(publicKeyStr string) (publicKey *rsa.PublicKey, err error) {
- block, _ := pem.Decode([]byte(publicKeyStr))
- if block == nil {
- return nil, errors.New("decode public key error")
- }
- if block.Type != "PUBLIC KEY" {
- return nil, fmt.Errorf("the kind of PEM should be PUBLIC KEY")
- }
- key, err := x509.ParsePKIXPublicKey(block.Bytes)
- if err != nil {
- return nil, fmt.Errorf("parse public key err:%s", err.Error())
- }
- publicKey, ok := key.(*rsa.PublicKey)
- if !ok {
- return nil, fmt.Errorf("%s is not rsa public key", publicKeyStr)
- }
- return publicKey, nil
- }
- // LoadPrivateKeyWithPath 通过私钥的文件路径内容加载私钥
- func LoadPrivateKeyWithPath(path string) (privateKey *rsa.PrivateKey, err error) {
- privateKeyBytes, err := os.ReadFile(path)
- if err != nil {
- return nil, fmt.Errorf("read private pem file err:%s", err.Error())
- }
- return LoadPrivateKey(string(privateKeyBytes))
- }
- // LoadPublicKeyWithPath 通过公钥的文件路径加载公钥
- func LoadPublicKeyWithPath(path string) (publicKey *rsa.PublicKey, err error) {
- publicKeyBytes, err := os.ReadFile(path)
- if err != nil {
- return nil, fmt.Errorf("read certificate pem file err:%s", err.Error())
- }
- return LoadPublicKey(string(publicKeyBytes))
- }
- // SignSHA256WithRSA 通过私钥对字符串以 SHA256WithRSA 算法生成签名信息
- func SignSHA256WithRSA(source string, privateKey *rsa.PrivateKey) (signature string, err error) {
- if privateKey == nil {
- return "", fmt.Errorf("private key should not be nil")
- }
- h := crypto.Hash.New(crypto.SHA256)
- _, err = h.Write([]byte(source))
- if err != nil {
- return "", nil
- }
- hashed := h.Sum(nil)
- signatureByte, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, hashed)
- if err != nil {
- return "", err
- }
- return base64.StdEncoding.EncodeToString(signatureByte), nil
- }
|