master
李光春 2 years ago
parent b15a3dc16d
commit b47d8317e2

@ -34,9 +34,9 @@ func NewCertificatesResult(result CertificatesResponse, body []byte, http gorequ
// Certificates 获取平台证书列表 // Certificates 获取平台证书列表
// https://pay.weixin.qq.com/wiki/doc/apiv3/apis/wechatpay5_1.shtml // https://pay.weixin.qq.com/wiki/doc/apiv3/apis/wechatpay5_1.shtml
func (app *App) Certificates() *CertificatesResult { func (c *Client) Certificates() *CertificatesResult {
// 请求 // 请求
request, err := app.request("https://api.mch.weixin.qq.com/v3/certificates", map[string]interface{}{}, http.MethodGet) request, err := c.request("https://api.mch.weixin.qq.com/v3/certificates", map[string]interface{}{}, http.MethodGet)
if err != nil { if err != nil {
return NewCertificatesResult(CertificatesResponse{}, request.ResponseBody, request, err) return NewCertificatesResult(CertificatesResponse{}, request.ResponseBody, request, err)
} }

@ -10,7 +10,7 @@ const (
// SDK 相关信息 // SDK 相关信息
const ( const (
Version = "1.0.0" // SDK 版本 Version = "1.0.1" // SDK 版本
UserAgentFormat = "WechatPay-Go/%s (%s) GO/%s" // UserAgent中的信息 UserAgentFormat = "WechatPay-Go/%s (%s) GO/%s" // UserAgent中的信息
) )

@ -22,26 +22,26 @@ type GetJsApiResult struct {
} }
// GetJsApi JSAPI调起支付API https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml // GetJsApi JSAPI调起支付API https://pay.weixin.qq.com/wiki/doc/apiv3/apis/chapter3_1_4.shtml
func (app *App) GetJsApi(param GetJsApi) (result GetJsApiResult, err error) { func (c *Client) GetJsApi(param GetJsApi) (result GetJsApiResult, err error) {
// sign params // sign params
timeStamp := time.Now().Unix() timeStamp := time.Now().Unix()
nonce := gorandom.Alphanumeric(32) nonce := gorandom.Alphanumeric(32)
result.AppId = app.subAppid result.AppId = c.config.SubAppid
result.TimeStamp = fmt.Sprintf("%v", timeStamp) // 时间戳 result.TimeStamp = fmt.Sprintf("%v", timeStamp) // 时间戳
result.NonceStr = nonce // 随机字符串 result.NonceStr = nonce // 随机字符串
result.Package = param.Package // 订单详情扩展字符串 result.Package = param.Package // 订单详情扩展字符串
// 签名 // 签名
message := fmt.Sprintf("%s\n%s\n%s\n%s\n", app.subAppid, fmt.Sprintf("%v", timeStamp), nonce, param.Package) message := fmt.Sprintf("%s\n%s\n%s\n%s\n", c.config.SubAppid, fmt.Sprintf("%v", timeStamp), nonce, param.Package)
signBytes, err := app.signPKCS1v15(message, []byte(app.mchSslKey)) signBytes, err := c.signPKCS1v15(message, []byte(c.config.MchSslKey))
if err != nil { if err != nil {
return result, err return result, err
} }
sign := app.base64EncodeStr(signBytes) sign := c.base64EncodeStr(signBytes)
result.PaySign = sign // 签名 result.PaySign = sign // 签名
result.SignType = "RSA" // 签名方式 result.SignType = "RSA" // 签名方式
return result, nil return result, nil

@ -64,12 +64,12 @@ func NewPayPartnerTransactionsIdResult(result PayPartnerTransactionsIdResponse,
// PayPartnerTransactionsId 微信支付订单号查询 // PayPartnerTransactionsId 微信支付订单号查询
// https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_2.shtml // https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_2.shtml
func (app *App) PayPartnerTransactionsId(transactionId string) *PayPartnerTransactionsIdResult { func (c *Client) PayPartnerTransactionsId(transactionId string) *PayPartnerTransactionsIdResult {
// 参数 // 参数
params := gorequest.NewParams() params := gorequest.NewParams()
// 请求 // 请求
// 请求 // 请求
request, err := app.request(fmt.Sprintf("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/id/%s?sp_mchid=%s&sub_mchid=%s", transactionId, app.spMchId, app.subMchId), params, http.MethodGet) request, err := c.request(fmt.Sprintf("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/id/%s?sp_mchid=%s&sub_mchid=%s", transactionId, c.config.SpMchId, c.config.SubMchId), params, http.MethodGet)
if err != nil { if err != nil {
return NewPayPartnerTransactionsIdResult(PayPartnerTransactionsIdResponse{}, request.ResponseBody, request, err) return NewPayPartnerTransactionsIdResult(PayPartnerTransactionsIdResponse{}, request.ResponseBody, request, err)
} }

@ -23,15 +23,15 @@ func NewPayPartnerTransactionsJsapiResult(result PayPartnerTransactionsJsapiResp
// PayPartnerTransactionsJsapi JSAPI下单 // PayPartnerTransactionsJsapi JSAPI下单
// https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_1.shtml // https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_1.shtml
func (app *App) PayPartnerTransactionsJsapi(notMustParams ...gorequest.Params) *PayPartnerTransactionsJsapiResult { func (c *Client) PayPartnerTransactionsJsapi(notMustParams ...gorequest.Params) *PayPartnerTransactionsJsapiResult {
// 参数 // 参数
params := gorequest.NewParamsWith(notMustParams...) params := gorequest.NewParamsWith(notMustParams...)
params.Set("sp_appid", app.spAppid) // 服务商应用ID params.Set("sp_appid", c.config.SpAppid) // 服务商应用ID
params.Set("sp_mchid", app.spMchId) // 服务商户号 params.Set("sp_mchid", c.config.SpMchId) // 服务商户号
params.Set("sub_appid", app.subAppid) // 子商户应用ID params.Set("sub_appid", c.config.SubAppid) // 子商户应用ID
params.Set("sub_mchid", app.subMchId) // 子商户号 params.Set("sub_mchid", c.config.SubMchId) // 子商户号
// 请求 // 请求
request, err := app.request("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi", params, http.MethodPost) request, err := c.request("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/jsapi", params, http.MethodPost)
if err != nil { if err != nil {
return NewPayPartnerTransactionsJsapiResult(PayPartnerTransactionsJsapiResponse{}, request.ResponseBody, request, err) return NewPayPartnerTransactionsJsapiResult(PayPartnerTransactionsJsapiResponse{}, request.ResponseBody, request, err)
} }

@ -18,13 +18,13 @@ func NewPayPartnerTransactionsOutTradeNoCloseResult(body []byte, http gorequest.
// PayPartnerTransactionsOutTradeNoClose 关闭订单API // PayPartnerTransactionsOutTradeNoClose 关闭订单API
// https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_3.shtml // https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_3.shtml
func (app *App) PayPartnerTransactionsOutTradeNoClose(outTradeNo string) *PayPartnerTransactionsOutTradeNoCloseResult { func (c *Client) PayPartnerTransactionsOutTradeNoClose(outTradeNo string) *PayPartnerTransactionsOutTradeNoCloseResult {
// 参数 // 参数
params := gorequest.NewParams() params := gorequest.NewParams()
params.Set("sp_mchid", app.spMchId) // 服务商户号 params.Set("sp_mchid", c.config.SpMchId) // 服务商户号
params.Set("sub_mchid", app.subMchId) // 子商户号 params.Set("sub_mchid", c.config.SubMchId) // 子商户号
// 请求 // 请求
request, err := app.request(fmt.Sprintf("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/%s/close", outTradeNo), params, http.MethodPost) request, err := c.request(fmt.Sprintf("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/%s/close", outTradeNo), params, http.MethodPost)
if err != nil { if err != nil {
return NewPayPartnerTransactionsOutTradeNoCloseResult(request.ResponseBody, request, err) return NewPayPartnerTransactionsOutTradeNoCloseResult(request.ResponseBody, request, err)
} }

@ -67,11 +67,11 @@ func NewPayPartnerTransactionsOutTradeNoResult(result PayPartnerTransactionsOutT
// PayPartnerTransactionsOutTradeNo 商户订单号查询 // PayPartnerTransactionsOutTradeNo 商户订单号查询
// https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_2.shtml // https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_2.shtml
func (app *App) PayPartnerTransactionsOutTradeNo(outTradeNo string) *PayPartnerTransactionsOutTradeNoResult { func (c *Client) PayPartnerTransactionsOutTradeNo(outTradeNo string) *PayPartnerTransactionsOutTradeNoResult {
// 参数 // 参数
params := gorequest.NewParams() params := gorequest.NewParams()
// 请求 // 请求
request, err := app.request(fmt.Sprintf("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/%s?sp_mchid=%s&sub_mchid=%s", outTradeNo, app.spMchId, app.subMchId), params, http.MethodGet) request, err := c.request(fmt.Sprintf("https://api.mch.weixin.qq.com/v3/pay/partner/transactions/out-trade-no/%s?sp_mchid=%s&sub_mchid=%s", outTradeNo, c.config.SpMchId, c.config.SubMchId), params, http.MethodGet)
if err != nil { if err != nil {
return NewPayPartnerTransactionsOutTradeNoResult(PayPartnerTransactionsOutTradeNoResponse{}, request.ResponseBody, request, err) return NewPayPartnerTransactionsOutTradeNoResult(PayPartnerTransactionsOutTradeNoResponse{}, request.ResponseBody, request, err)
} }

@ -62,12 +62,12 @@ func NewRefundDomesticRefundsResult(result RefundDomesticRefundsResponse, body [
// RefundDomesticRefunds 申请退款API // RefundDomesticRefunds 申请退款API
// https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_9.shtml // https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_9.shtml
func (app *App) RefundDomesticRefunds(notMustParams ...gorequest.Params) *RefundDomesticRefundsResult { func (c *Client) RefundDomesticRefunds(notMustParams ...gorequest.Params) *RefundDomesticRefundsResult {
// 参数 // 参数
params := gorequest.NewParamsWith(notMustParams...) params := gorequest.NewParamsWith(notMustParams...)
params.Set("sub_mchid", app.subMchId) // 子商户号 params.Set("sub_mchid", c.config.SubMchId) // 子商户号
// 请求 // 请求
request, err := app.request("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds", params, http.MethodPost) request, err := c.request("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds", params, http.MethodPost)
if err != nil { if err != nil {
return NewRefundDomesticRefundsResult(RefundDomesticRefundsResponse{}, request.ResponseBody, request, err) return NewRefundDomesticRefundsResult(RefundDomesticRefundsResponse{}, request.ResponseBody, request, err)
} }

@ -62,11 +62,11 @@ func NewRefundDomesticRefundsOutRefundNoResult(result RefundDomesticRefundsOutRe
// RefundDomesticRefundsOutRefundNo 查询单笔退款API // RefundDomesticRefundsOutRefundNo 查询单笔退款API
// https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_9.shtml // https://pay.weixin.qq.com/wiki/doc/apiv3_partner/apis/chapter4_5_9.shtml
func (app *App) RefundDomesticRefundsOutRefundNo(outRefundNo string) *RefundDomesticRefundsOutRefundNoResult { func (c *Client) RefundDomesticRefundsOutRefundNo(outRefundNo string) *RefundDomesticRefundsOutRefundNoResult {
// 参数 // 参数
params := gorequest.NewParams() params := gorequest.NewParams()
// 请求 // 请求
request, err := app.request("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/"+outRefundNo+"?sub_mchid="+app.subMchId, params, http.MethodGet) request, err := c.request("https://api.mch.weixin.qq.com/v3/refund/domestic/refunds/"+outRefundNo+"?sub_mchid="+c.config.SubMchId, params, http.MethodGet)
if err != nil { if err != nil {
return NewRefundDomesticRefundsOutRefundNoResult(RefundDomesticRefundsOutRefundNoResponse{}, request.ResponseBody, request, err) return NewRefundDomesticRefundsOutRefundNoResult(RefundDomesticRefundsOutRefundNoResponse{}, request.ResponseBody, request, err)
} }

@ -19,7 +19,7 @@ import (
) )
// 对消息的散列值进行数字签名 // 对消息的散列值进行数字签名
func (app *App) signPKCS1v15(msg string, privateKey []byte) ([]byte, error) { func (c *Client) signPKCS1v15(msg string, privateKey []byte) ([]byte, error) {
block, _ := pem.Decode(privateKey) block, _ := pem.Decode(privateKey)
if block == nil { if block == nil {
@ -36,7 +36,7 @@ func (app *App) signPKCS1v15(msg string, privateKey []byte) ([]byte, error) {
return nil, errors.New("private key format error") return nil, errors.New("private key format error")
} }
sign, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, app.haSha256(msg)) sign, err := rsa.SignPKCS1v15(rand.Reader, key, crypto.SHA256, c.haSha256(msg))
if err != nil { if err != nil {
return nil, errors.New("sign error") return nil, errors.New("sign error")
} }
@ -45,12 +45,12 @@ func (app *App) signPKCS1v15(msg string, privateKey []byte) ([]byte, error) {
} }
// base编码 // base编码
func (app *App) base64EncodeStr(src []byte) string { func (c *Client) base64EncodeStr(src []byte) string {
return base64.StdEncoding.EncodeToString(src) return base64.StdEncoding.EncodeToString(src)
} }
// sha256加密 // sha256加密
func (app *App) haSha256(str string) []byte { func (c *Client) haSha256(str string) []byte {
h := sha256.New() h := sha256.New()
h.Write([]byte(str)) h.Write([]byte(str))
return h.Sum(nil) return h.Sum(nil)
@ -58,7 +58,7 @@ func (app *App) haSha256(str string) []byte {
// 生成身份认证信息 // 生成身份认证信息
// https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/qian-ming-sheng-cheng // https://wechatpay-api.gitbook.io/wechatpay-api-v3/qian-ming-zhi-nan-1/qian-ming-sheng-cheng
func (app *App) authorization(method string, paramMap map[string]interface{}, rawUrl string) (token string, err error) { func (c *Client) authorization(method string, paramMap map[string]interface{}, rawUrl string) (token string, err error) {
// 请求报文主体 // 请求报文主体
var signBody string var signBody string
@ -86,7 +86,7 @@ func (app *App) authorization(method string, paramMap map[string]interface{}, ra
// 构造签名串 // 构造签名串
message := fmt.Sprintf(SignatureMessageFormat, method, canonicalUrl, timestamp, nonce, signBody) message := fmt.Sprintf(SignatureMessageFormat, method, canonicalUrl, timestamp, nonce, signBody)
sign, err := app.signSHA256WithRSA(message, app.getRsa([]byte(app.mchSslKey))) sign, err := c.signSHA256WithRSA(message, c.getRsa([]byte(c.config.MchSslKey)))
if err != nil { if err != nil {
return token, err return token, err
@ -94,14 +94,14 @@ func (app *App) authorization(method string, paramMap map[string]interface{}, ra
authorization := fmt.Sprintf( authorization := fmt.Sprintf(
HeaderAuthorizationFormat, getAuthorizationType(), HeaderAuthorizationFormat, getAuthorizationType(),
app.spMchId, nonce, timestamp, app.mchSslSerialNo, sign, c.config.SpMchId, nonce, timestamp, c.config.MchSslSerialNo, sign,
) )
return authorization, nil return authorization, nil
} }
// 报文解密 // 报文解密
func (app *App) decryptGCM(aesKey, nonceV, ciphertextV, additionalDataV string) ([]byte, error) { func (c *Client) decryptGCM(aesKey, nonceV, ciphertextV, additionalDataV string) ([]byte, error) {
key := []byte(aesKey) key := []byte(aesKey)
nonce := []byte(nonceV) nonce := []byte(nonceV)
additionalData := []byte(additionalDataV) additionalData := []byte(additionalDataV)
@ -125,7 +125,7 @@ func (app *App) decryptGCM(aesKey, nonceV, ciphertextV, additionalDataV string)
} }
// 对消息的散列值进行数字签名 // 对消息的散列值进行数字签名
func (app *App) getRsa(privateKey []byte) *rsa.PrivateKey { func (c *Client) getRsa(privateKey []byte) *rsa.PrivateKey {
block, _ := pem.Decode(privateKey) block, _ := pem.Decode(privateKey)
if block == nil { if block == nil {
@ -146,7 +146,7 @@ func (app *App) getRsa(privateKey []byte) *rsa.PrivateKey {
} }
// 通过私钥对字符串以 SHA256WithRSA 算法生成签名信息 // 通过私钥对字符串以 SHA256WithRSA 算法生成签名信息
func (app *App) signSHA256WithRSA(source string, privateKey *rsa.PrivateKey) (signature string, err error) { func (c *Client) signSHA256WithRSA(source string, privateKey *rsa.PrivateKey) (signature string, err error) {
if privateKey == nil { if privateKey == nil {
return "", fmt.Errorf("private key should not be nil") return "", fmt.Errorf("private key should not be nil")
} }

@ -6,58 +6,64 @@ import (
"gorm.io/gorm" "gorm.io/gorm"
) )
// App 微信支付服务器 type ConfigClient struct {
type App struct { SpAppid string // 服务商应用ID
spAppid string // 服务商应用ID SpMchId string // 服务商户号
spMchId string // 服务商户号 SubAppid string // 子商户应用ID
subAppid string // 子商户应用ID SubMchId string // 子商户号
subMchId string // 子商户号 ApiV2 string // APIv2密钥
apiV2 string // APIv2密钥 ApiV3 string // APIv3密钥
apiV3 string // APIv3密钥 SerialNo string // 序列号
serialNo string // 序列号 MchSslSerialNo string // pem 证书号
mchSslSerialNo string // pem 证书号 MchSslCer string // pem 内容
mchSslCer string // pem 内容 MchSslKey string // pem key 内容
mchSslKey string // pem key 内容 PgsqlDb *gorm.DB // pgsql数据库
pgsql *gorm.DB // pgsql数据库
client *gorequest.App // 请求客户端
log *golog.Api // 日志服务
logTableName string // 日志表名
logStatus bool // 日志状态
} }
// NewApp 实例化 // Client 微信支付服务
func NewApp(spAppid, spMchId, subAppid, subMchId, apiV2, apiV3, serialNo, mchSslSerialNo, mchSslCer, mchSslKey string, pgsql *gorm.DB) *App { type Client struct {
app := &App{spAppid: spAppid, spMchId: spMchId, subAppid: subAppid, subMchId: subMchId, apiV2: apiV2, apiV3: apiV3, serialNo: serialNo, mchSslSerialNo: mchSslSerialNo, mchSslCer: mchSslCer, mchSslKey: mchSslKey} client *gorequest.App // 请求客户端
app.client = gorequest.NewHttp() log *golog.Api // 日志服务
if pgsql != nil { logTableName string // 日志表名
app.pgsql = pgsql logStatus bool // 日志状态
app.logStatus = true config *ConfigClient // 配置
app.logTableName = "wechatpayopen" }
app.log = golog.NewApi(&golog.ApiConfig{
Db: pgsql, // NewClient 实例化
TableName: app.logTableName, func NewClient(config *ConfigClient) *Client {
c := &Client{config: config}
c.client = gorequest.NewHttp()
if c.config.PgsqlDb != nil {
c.logStatus = true
c.logTableName = "wechatpayopen"
c.log = golog.NewApi(&golog.ApiConfig{
Db: c.config.PgsqlDb,
TableName: c.logTableName,
}) })
} }
return app
return c
} }
// NewAppConfig 实例化 // SubConfig 子商户配置
func (app *App) NewAppConfig(subAppid, subMchId string) *App { func (c *Client) SubConfig(subAppid, subMchId string) *Client {
app.subAppid = subAppid c.config.SpAppid = subAppid
app.subMchId = subMchId c.config.SubMchId = subMchId
return app return c
} }
func (app *App) request(url string, params map[string]interface{}, method string) (resp gorequest.Response, err error) { func (c *Client) request(url string, params map[string]interface{}, method string) (resp gorequest.Response, err error) {
// 认证 // 认证
authorization, err := app.authorization(method, params, url) authorization, err := c.authorization(method, params, url)
if err != nil { if err != nil {
return gorequest.Response{}, err return gorequest.Response{}, err
} }
// 创建请求 // 创建请求
client := app.client client := c.client
// 设置请求地址 // 设置请求地址
client.SetUri(url) client.SetUri(url)
@ -83,8 +89,8 @@ func (app *App) request(url string, params map[string]interface{}, method string
} }
// 日志 // 日志
if app.logStatus == true { if c.logStatus == true {
go app.postgresqlLog(request) go c.postgresqlLog(request)
} }
return request, err return request, err

Loading…
Cancel
Save