service/vendor/github.com/go-pay/gopay/wechat/sign.go

216 lines
6.9 KiB
Go
Raw Normal View History

2024-02-20 23:05:24 +08:00
package wechat
import (
"context"
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"errors"
"fmt"
"hash"
"reflect"
"strings"
"github.com/go-pay/gopay"
"github.com/go-pay/gopay/pkg/util"
)
// VerifySign 微信同步返回参数验签或异步通知参数验签
// ApiKeyAPI秘钥值
// signType签名类型调用API方法时填写的类型
// bean微信同步返回的结构体 wxRsp 或 异步通知解析的结构体 notifyReq推荐通 BodyMap 验签
// 返回参数ok是否验签通过
// 返回参数err其他错误信息不要根据 error 是否为空来判断验签正确与否,需再单独判断返回的 ok
func VerifySign(apiKey, signType string, bean interface{}) (ok bool, err error) {
if bean == nil {
return false, errors.New("bean is nil")
}
kind := reflect.ValueOf(bean).Kind()
if kind == reflect.Map {
bm := bean.(gopay.BodyMap)
bodySign := bm.GetString("sign")
bm.Remove("sign")
return GetReleaseSign(apiKey, signType, bm) == bodySign, nil
}
bs, err := json.Marshal(bean)
if err != nil {
return false, fmt.Errorf("json.Marshal(%s)%w", string(bs), err)
}
bm := make(gopay.BodyMap)
if err = json.Unmarshal(bs, &bm); err != nil {
return false, fmt.Errorf("json.Marshal(%s)%w", string(bs), err)
}
bodySign := bm.GetString("sign")
bm.Remove("sign")
return GetReleaseSign(apiKey, signType, bm) == bodySign, nil
}
// GetMiniPaySign JSAPI支付统一下单获取支付参数后再次计算出小程序用的paySign
// appIdAPPID
// nonceStr随即字符串
// packages统一下单成功后拼接得到的值
// signType签名类型
// timeStamp时间
// ApiKeyAPI秘钥值
// 微信小程序支付APIhttps://developers.weixin.qq.com/miniprogram/dev/api/open-api/payment/wx.requestPayment.html
// 微信小程序支付PaySign计算文档https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=7_7&index=3
func GetMiniPaySign(appId, nonceStr, packages, signType, timeStamp, apiKey string) (paySign string) {
var (
buffer strings.Builder
h hash.Hash
)
buffer.WriteString("appId=")
buffer.WriteString(appId)
buffer.WriteString("&nonceStr=")
buffer.WriteString(nonceStr)
buffer.WriteString("&package=")
buffer.WriteString(packages)
buffer.WriteString("&signType=")
buffer.WriteString(signType)
buffer.WriteString("&timeStamp=")
buffer.WriteString(timeStamp)
buffer.WriteString("&key=")
buffer.WriteString(apiKey)
if signType == SignType_HMAC_SHA256 {
h = hmac.New(sha256.New, []byte(apiKey))
} else {
h = md5.New()
}
h.Write([]byte(buffer.String()))
return strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
}
// Deprecated
// 微信内H5支付官方文档https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
func GetH5PaySign(appId, nonceStr, packages, signType, timeStamp, apiKey string) (paySign string) {
return GetJsapiPaySign(appId, nonceStr, packages, signType, timeStamp, apiKey)
}
// GetJsapiPaySign JSAPI调起支付统一下单获取支付参数后再次计算出微信内H5支付需要用的paySign
// appIdAPPID
// nonceStr随即字符串
// packages统一下单成功后拼接得到的值
// signType签名类型
// timeStamp时间
// ApiKeyAPI秘钥值
// 文档https://pay.weixin.qq.com/wiki/doc/api/jsapi.php?chapter=7_7&index=6
func GetJsapiPaySign(appId, nonceStr, packages, signType, timeStamp, apiKey string) (paySign string) {
var (
buffer strings.Builder
h hash.Hash
)
buffer.WriteString("appId=")
buffer.WriteString(appId)
buffer.WriteString("&nonceStr=")
buffer.WriteString(nonceStr)
buffer.WriteString("&package=")
buffer.WriteString(packages)
buffer.WriteString("&signType=")
buffer.WriteString(signType)
buffer.WriteString("&timeStamp=")
buffer.WriteString(timeStamp)
buffer.WriteString("&key=")
buffer.WriteString(apiKey)
if signType == SignType_HMAC_SHA256 {
h = hmac.New(sha256.New, []byte(apiKey))
} else {
h = md5.New()
}
h.Write([]byte(buffer.String()))
paySign = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
return
}
// GetAppPaySign APP支付统一下单获取支付参数后再次计算APP支付所需要的的sign
// appIdAPPID
// partneridpartnerid
// nonceStr随即字符串
// prepayId统一下单成功后得到的值
// signType此处签名方式务必与统一下单时用的签名方式一致
// timeStamp时间
// ApiKeyAPI秘钥值
// 文档https://pay.weixin.qq.com/wiki/doc/api/app/app.php?chapter=9_12&index=2
func GetAppPaySign(appid, partnerid, noncestr, prepayid, signType, timestamp, apiKey string) (paySign string) {
var (
buffer strings.Builder
h hash.Hash
)
buffer.WriteString("appid=")
buffer.WriteString(appid)
buffer.WriteString("&noncestr=")
buffer.WriteString(noncestr)
buffer.WriteString("&package=Sign=WXPay")
buffer.WriteString("&partnerid=")
buffer.WriteString(partnerid)
buffer.WriteString("&prepayid=")
buffer.WriteString(prepayid)
buffer.WriteString("&timestamp=")
buffer.WriteString(timestamp)
buffer.WriteString("&key=")
buffer.WriteString(apiKey)
if signType == SignType_HMAC_SHA256 {
h = hmac.New(sha256.New, []byte(apiKey))
} else {
h = md5.New()
}
h.Write([]byte(buffer.String()))
paySign = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
return
}
// Deprecated
// GetParamSign 获取微信支付所需参数里的Sign值通过支付参数计算Sign值
// 注意BodyMap中如无 sign_type 参数,默认赋值 sign_type 为 MD5
// appId应用ID
// mchId商户ID
// ApiKeyAPI秘钥值
// 返回参数 sign通过Appid、MchId、ApiKey和BodyMap中的参数计算出的Sign值
func GetParamSign(appId, mchId, apiKey string, bm gopay.BodyMap) (sign string) {
bm.Set("appid", appId)
bm.Set("mch_id", mchId)
var (
signType string
h hash.Hash
)
signType = bm.GetString("sign_type")
if signType == util.NULL {
bm.Set("sign_type", SignType_MD5)
}
if signType == SignType_HMAC_SHA256 {
h = hmac.New(sha256.New, []byte(apiKey))
} else {
h = md5.New()
}
h.Write([]byte(bm.EncodeWeChatSignParams(apiKey)))
sign = strings.ToUpper(hex.EncodeToString(h.Sum(nil)))
return
}
// Deprecated
// GetSanBoxParamSign 获取微信支付沙箱环境所需参数里的Sign值通过支付参数计算Sign值
// 注意:沙箱环境默认 sign_type 为 MD5
// appId应用ID
// mchId商户ID
// ApiKeyAPI秘钥值
// 返回参数 sign通过Appid、MchId、ApiKey和BodyMap中的参数计算出的Sign值
func GetSanBoxParamSign(ctx context.Context, appId, mchId, apiKey string, bm gopay.BodyMap) (sign string, err error) {
bm.Set("appid", appId)
bm.Set("mch_id", mchId)
bm.Set("sign_type", SignType_MD5)
bm.Set("total_fee", 101)
var (
sandBoxApiKey string
hashMd5 hash.Hash
)
if sandBoxApiKey, err = getSanBoxKey(ctx, mchId, util.RandomString(32), apiKey, SignType_MD5); err != nil {
return
}
hashMd5 = md5.New()
hashMd5.Write([]byte(bm.EncodeWeChatSignParams(sandBoxApiKey)))
sign = strings.ToUpper(hex.EncodeToString(hashMd5.Sum(nil)))
return
}