123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160 |
- package pay
- import (
- "crypto"
- "crypto/rand"
- "crypto/rsa"
- "crypto/x509"
- "encoding/base64"
- "encoding/pem"
- "errors"
- "fmt"
- "io/ioutil"
- "net/http"
- "net/url"
- "strings"
- "time"
- "zhiyuan/models"
- "zhiyuan/pkg/config"
- "zhiyuan/pkg/utils"
- "zhiyuan/services/weixin"
- )
- const (
- JsapiUrl = "https://api.mch.weixin.qq.com/v3/pay/transactions/jsapi"
- HeaderAuthorizationFormat = "WECHATPAY2-SHA256-RSA2048 mchid=\"%s\",nonce_str=\"%s\",timestamp=\"%d\",serial_no=\"%s\",signature=\"%s\""
- Authorization = "Authorization"
- Accept = "Accept"
- )
- type Client struct {
- Account *models.Weixin // 支付账号
- SignType string // 签名类型
- PrivateKey *rsa.PrivateKey
- }
- func NewClient(wxID int) (*Client, error) {
- weixinInfo, _ := weixin.GetOne(map[string]interface{}{"id": wxID}, nil, nil)
- private, err := LoadPrivateKey()
- if err != nil {
- return nil, err
- }
- return &Client{
- Account: weixinInfo,
- SignType: "RSA",
- PrivateKey: private,
- }, nil
- }
- func (c *Client) SignRequest(method string, requestUrl string, body string) (string, error) {
- u, err := url.Parse(requestUrl)
- timestamp := time.Now().Unix()
- nonce := utils.RandomStr()
- sign, err := c.Sign([]string{method, u.RequestURI(), utils.ToStr(timestamp), nonce, body})
- if err != nil {
- return "", err
- }
- return fmt.Sprintf(HeaderAuthorizationFormat,
- c.Account.MchID,
- nonce,
- timestamp,
- c.Account.SerialNO,
- sign,
- ), nil
- }
- func (c *Client) Sign(param []string) (string, error) {
- message := strings.Join(param, "\n") + "\n"
- return SignSHA256WithRSA(message, c.PrivateKey)
- }
- func (c *Client) Prepay(param JsapiParam) (*PrepayResponse, error) {
- if param.Description == "" || param.OutTradeNO == "" || param.Total <= 0 || param.OpenID == "" {
- return nil, errors.New("description,out_trade_no,open_id,money不能为空")
- }
- params := PrepayRequest{
- AppID: c.Account.AppID,
- MchID: c.Account.MchID,
- Description: param.Description,
- OutTradeNO: param.OutTradeNO,
- NotifyUrl: param.NotifyUrl,
- }
- params.Amount.Total = utils.FloatMul(param.Total, 100, 0)
- params.Payer.OpenID = param.OpenID
- fmt.Println(params)
- authorization, err := c.SignRequest("POST", JsapiUrl, utils.JsonEncode(params))
- if err != nil {
- return nil, err
- }
- header := SetHeaderAuthorization(authorization)
- var res *PrepayResponse
- if err := utils.HttpPostJSON(&http.Client{}, JsapiUrl, header, params, &res); err != nil {
- return nil, err
- }
- if res.PrepayID == "" {
- return nil, errors.New(res.Message)
- }
- return res, nil
- }
- func (c *Client) JsapiPay(param JsapiParam) (JsapiReturn, error) {
- res, err := c.Prepay(param)
- if err != nil {
- return JsapiReturn{}, err
- }
- retParam := JsapiReturn{
- AppID: c.Account.AppID,
- Timestamp: utils.ToStr(time.Now().Unix()),
- NonceStr: utils.RandomStr(),
- Package: "prepay_id=" + res.PrepayID,
- SignType: c.SignType,
- }
- if sign, err := c.Sign([]string{retParam.AppID, retParam.Timestamp, retParam.NonceStr, retParam.SignType}); err != nil {
- return JsapiReturn{}, err
- } else {
- retParam.PaySign = sign
- return retParam, nil
- }
- }
- func SetHeaderAuthorization(authorization string) http.Header {
- header := http.Header{}
- header.Set(Authorization, authorization)
- header.Set(Accept, "*/*")
- return header
- }
- func LoadPrivateKey() (*rsa.PrivateKey, error) {
- privateKeyStr, err := ioutil.ReadFile(utils.GetRootPath() + config.Cfg.App.WeixinPath + "apiclient_key.pem")
- block, _ := pem.Decode(privateKeyStr)
- if block == nil {
- return nil, fmt.Errorf("decode private key err")
- }
- 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("%s is not rsa private key", privateKeyStr)
- }
- return privateKey, nil
- }
- 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
- }
|