Jerry 6 лет назад
Родитель
Сommit
70c5f2622a
7 измененных файлов с 101 добавлено и 78 удалено
  1. 0 18
      alipay_service_api.go
  2. 2 2
      examples/wechat/wx_UnifiedOrder.go
  3. 22 5
      util.go
  4. 8 5
      wechat_client.go
  5. BIN
      wechat_gopay.png
  6. 27 6
      wechat_params.go
  7. 42 42
      wechat_rsp.go

+ 0 - 18
alipay_service_api.go

@@ -173,24 +173,6 @@ func verifyAliPaySign(signData, sign, signType, aliPayPublicKey string) (err err
 	return rsa.VerifyPKCS1v15(publicKey, hashs, h.Sum(nil), signBytes)
 	return rsa.VerifyPKCS1v15(publicKey, hashs, h.Sum(nil), signBytes)
 }
 }
 
 
-func jsonToString(v interface{}) (str string) {
-	if v == nil {
-		return null
-	}
-	var (
-		bs  []byte
-		err error
-	)
-	if bs, err = json.Marshal(v); err != nil {
-		return null
-	}
-
-	if str = string(bs); str == null {
-		return null
-	}
-	return
-}
-
 //格式化 普通应用秘钥
 //格式化 普通应用秘钥
 func FormatPrivateKey(privateKey string) (pKey string) {
 func FormatPrivateKey(privateKey string) (pKey string) {
 	var buffer strings.Builder
 	var buffer strings.Builder

+ 2 - 2
examples/wechat/wx_UnifiedOrder.go

@@ -43,9 +43,9 @@ func UnifiedOrder() {
 
 
 	//body.Set("openid", "o0Df70H2Q0fY8JXh1aFPIRyOBgu8")
 	//body.Set("openid", "o0Df70H2Q0fY8JXh1aFPIRyOBgu8")
 
 
-	sign := gopay.GetWeChatParamSign("wxdaa2ab9ef87b5497", "1368139502", "GFDS8j98rewnmgl45wHTt980jg543abc", body)
+	//sign := gopay.GetWeChatParamSign("wxdaa2ab9ef87b5497", "1368139502", "GFDS8j98rewnmgl45wHTt980jg543abc", body)
 	//sign, _ := gopay.GetWeChatSanBoxParamSign("wxdaa2ab9ef87b5497", "1368139502", "GFDS8j98rewnmgl45wHTt980jg543abc", body)
 	//sign, _ := gopay.GetWeChatSanBoxParamSign("wxdaa2ab9ef87b5497", "1368139502", "GFDS8j98rewnmgl45wHTt980jg543abc", body)
-	body.Set("sign", sign)
+	//body.Set("sign", sign)
 
 
 	//请求支付下单,成功后得到结果
 	//请求支付下单,成功后得到结果
 	wxRsp, err := client.UnifiedOrder(body)
 	wxRsp, err := client.UnifiedOrder(body)

+ 22 - 5
util.go

@@ -2,6 +2,7 @@ package gopay
 
 
 import (
 import (
 	"crypto/tls"
 	"crypto/tls"
+	"encoding/json"
 	"encoding/xml"
 	"encoding/xml"
 	"io"
 	"io"
 	"math/rand"
 	"math/rand"
@@ -57,6 +58,21 @@ func (bm BodyMap) Get(key string) string {
 	return jsonToString(value)
 	return jsonToString(value)
 }
 }
 
 
+func jsonToString(v interface{}) (str string) {
+	if v == nil {
+		return null
+	}
+	var (
+		bs  []byte
+		err error
+	)
+	if bs, err = json.Marshal(v); err != nil {
+		return null
+	}
+	str = string(bs)
+	return
+}
+
 //删除参数
 //删除参数
 func (bm BodyMap) Remove(key string) {
 func (bm BodyMap) Remove(key string) {
 	delete(bm, key)
 	delete(bm, key)
@@ -119,16 +135,17 @@ func (bm BodyMap) EncodeWeChatSignParams(apiKey string) string {
 		buf     strings.Builder
 		buf     strings.Builder
 		keyList []string
 		keyList []string
 	)
 	)
-	keyList = make([]string, 0, len(bm))
 	for k := range bm {
 	for k := range bm {
 		keyList = append(keyList, k)
 		keyList = append(keyList, k)
 	}
 	}
 	sort.Strings(keyList)
 	sort.Strings(keyList)
 	for _, k := range keyList {
 	for _, k := range keyList {
-		buf.WriteString(k)
-		buf.WriteByte('=')
-		buf.WriteString(bm.Get(k))
-		buf.WriteByte('&')
+		if v := bm.Get(k); v != null {
+			buf.WriteString(k)
+			buf.WriteByte('=')
+			buf.WriteString(v)
+			buf.WriteByte('&')
+		}
 	}
 	}
 	buf.WriteString("key")
 	buf.WriteString("key")
 	buf.WriteByte('=')
 	buf.WriteByte('=')

+ 8 - 5
wechat_client.go

@@ -13,11 +13,14 @@ import (
 )
 )
 
 
 type WeChatClient struct {
 type WeChatClient struct {
-	AppId   string
-	MchId   string
-	ApiKey  string
-	BaseURL string
-	IsProd  bool
+	AppId      string
+	MchId      string
+	ApiKey     string
+	BaseURL    string
+	CertFile   []byte
+	KeyFile    []byte
+	Pkcs12File []byte
+	IsProd     bool
 }
 }
 
 
 // 初始化微信客户端 ok
 // 初始化微信客户端 ok

BIN
wechat_gopay.png


+ 27 - 6
wechat_params.go

@@ -8,12 +8,13 @@ import (
 	"encoding/xml"
 	"encoding/xml"
 	"errors"
 	"errors"
 	"hash"
 	"hash"
+	"io/ioutil"
 	"strings"
 	"strings"
 )
 )
 
 
 type Country int
 type Country int
 
 
-//设置支付国家(默认:中国国内)
+// 设置支付国家(默认:中国国内)
 //    根据支付地区情况设置国家
 //    根据支付地区情况设置国家
 //    country:<China:中国国内,China2:中国国内(冗灾方案),SoutheastAsia:东南亚,Other:其他国家>
 //    country:<China:中国国内,China2:中国国内(冗灾方案),SoutheastAsia:东南亚,Other:其他国家>
 func (w *WeChatClient) SetCountry(country Country) (client *WeChatClient) {
 func (w *WeChatClient) SetCountry(country Country) (client *WeChatClient) {
@@ -32,7 +33,27 @@ func (w *WeChatClient) SetCountry(country Country) (client *WeChatClient) {
 	return w
 	return w
 }
 }
 
 
-//获取微信支付正式环境Sign值
+// 添加微信证书Bytes
+func (w *WeChatClient) AddCertFileBytes(certFile, keyFile, pkcs12File []byte) {
+	w.CertFile = certFile
+	w.KeyFile = keyFile
+	w.Pkcs12File = pkcs12File
+}
+
+// 添加微信证书Path路径
+func (w *WeChatClient) AddCertFilePath(certFilePath, keyFilePath, pkcs12FilePath string) {
+	if cert, err := ioutil.ReadFile(certFilePath); err == nil {
+		w.CertFile = cert
+	}
+	if key, err := ioutil.ReadFile(keyFilePath); err == nil {
+		w.KeyFile = key
+	}
+	if pkcs, err := ioutil.ReadFile(pkcs12FilePath); err == nil {
+		w.Pkcs12File = pkcs
+	}
+}
+
+// 获取微信支付正式环境Sign值
 func getWeChatReleaseSign(apiKey string, signType string, bm BodyMap) (sign string) {
 func getWeChatReleaseSign(apiKey string, signType string, bm BodyMap) (sign string) {
 	var h hash.Hash
 	var h hash.Hash
 	if signType == SignType_HMAC_SHA256 {
 	if signType == SignType_HMAC_SHA256 {
@@ -45,7 +66,7 @@ func getWeChatReleaseSign(apiKey string, signType string, bm BodyMap) (sign stri
 	return
 	return
 }
 }
 
 
-//获取微信支付沙箱环境Sign值
+// 获取微信支付沙箱环境Sign值
 func getWeChatSignBoxSign(mchId, apiKey string, bm BodyMap) (sign string, err error) {
 func getWeChatSignBoxSign(mchId, apiKey string, bm BodyMap) (sign string, err error) {
 	var (
 	var (
 		sandBoxApiKey string
 		sandBoxApiKey string
@@ -60,7 +81,7 @@ func getWeChatSignBoxSign(mchId, apiKey string, bm BodyMap) (sign string, err er
 	return
 	return
 }
 }
 
 
-//从微信提供的接口获取:SandboxSignKey
+// 从微信提供的接口获取:SandboxSignKey
 func getSanBoxKey(mchId, nonceStr, apiKey, signType string) (key string, err error) {
 func getSanBoxKey(mchId, nonceStr, apiKey, signType string) (key string, err error) {
 	body := make(BodyMap)
 	body := make(BodyMap)
 	body.Set("mch_id", mchId)
 	body.Set("mch_id", mchId)
@@ -72,7 +93,7 @@ func getSanBoxKey(mchId, nonceStr, apiKey, signType string) (key string, err err
 	return
 	return
 }
 }
 
 
-//从微信提供的接口获取:SandboxSignkey
+// 从微信提供的接口获取:SandboxSignkey
 func getSanBoxSignKey(mchId, nonceStr, sign string) (key string, err error) {
 func getSanBoxSignKey(mchId, nonceStr, sign string) (key string, err error) {
 	reqs := make(BodyMap)
 	reqs := make(BodyMap)
 	reqs.Set("mch_id", mchId)
 	reqs.Set("mch_id", mchId)
@@ -96,7 +117,7 @@ func getSanBoxSignKey(mchId, nonceStr, sign string) (key string, err error) {
 	return keyResponse.SandboxSignkey, nil
 	return keyResponse.SandboxSignkey, nil
 }
 }
 
 
-//生成请求XML的Body体
+// 生成请求XML的Body体
 func generateXml(bm BodyMap) (reqXml string) {
 func generateXml(bm BodyMap) (reqXml string) {
 	var buffer strings.Builder
 	var buffer strings.Builder
 	buffer.WriteString("<xml>")
 	buffer.WriteString("<xml>")

+ 42 - 42
wechat_rsp.go

@@ -252,50 +252,50 @@ type WeChatNotifyRequest struct {
 }
 }
 
 
 type Code2SessionRsp struct {
 type Code2SessionRsp struct {
-	SessionKey string `json:"session_key,omitempty"` //会话密钥
-	ExpiresIn  int    `json:"expires_in,omitempty"`  //SessionKey超时时间(秒)
-	Openid     string `json:"openid,omitempty"`      //用户唯一标识
-	Unionid    string `json:"unionid,omitempty"`     //用户在开放平台的唯一标识符
-	Errcode    int    `json:"errcode,omitempty"`     //错误码
-	Errmsg     string `json:"errmsg,omitempty"`      //错误信息
+	SessionKey string `json:"session_key,omitempty"` // 会话密钥
+	ExpiresIn  int    `json:"expires_in,omitempty"`  // SessionKey超时时间(秒)
+	Openid     string `json:"openid,omitempty"`      // 用户唯一标识
+	Unionid    string `json:"unionid,omitempty"`     // 用户在开放平台的唯一标识符
+	Errcode    int    `json:"errcode,omitempty"`     // 错误码
+	Errmsg     string `json:"errmsg,omitempty"`      // 错误信息
 }
 }
 
 
 type PaidUnionId struct {
 type PaidUnionId struct {
-	Unionid string `json:"unionid,omitempty"` //用户在开放平台的唯一标识符
-	Errcode int    `json:"errcode,omitempty"` //错误码
-	Errmsg  string `json:"errmsg,omitempty"`  //错误信息
+	Unionid string `json:"unionid,omitempty"` // 用户在开放平台的唯一标识符
+	Errcode int    `json:"errcode,omitempty"` // 错误码
+	Errmsg  string `json:"errmsg,omitempty"`  // 错误信息
 }
 }
 
 
 type AccessToken struct {
 type AccessToken struct {
-	AccessToken string `json:"access_token,omitempty"` //获取到的凭证
-	ExpiresIn   int    `json:"expires_in,omitempty"`   //SessionKey超时时间(秒)
-	Errcode     int    `json:"errcode,omitempty"`      //错误码
-	Errmsg      string `json:"errmsg,omitempty"`       //错误信息
+	AccessToken string `json:"access_token,omitempty"` // 获取到的凭证
+	ExpiresIn   int    `json:"expires_in,omitempty"`   // SessionKey超时时间(秒)
+	Errcode     int    `json:"errcode,omitempty"`      // 错误码
+	Errmsg      string `json:"errmsg,omitempty"`       // 错误信息
 }
 }
 
 
 type WeChatUserInfo struct {
 type WeChatUserInfo struct {
-	Subscribe      int    `json:"subscribe,omitempty"`       //用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。
-	Openid         string `json:"openid,omitempty"`          //用户唯一标识
-	Nickname       string `json:"nickname,omitempty"`        //用户的昵称
-	Sex            int    `json:"sex,omitempty"`             //用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
-	Language       string `json:"language,omitempty"`        //用户的语言,简体中文为zh_CN
-	City           string `json:"city,omitempty"`            //用户所在城市
-	Province       string `json:"province,omitempty"`        //用户所在省份
-	Country        string `json:"country,omitempty"`         //用户所在国家
-	Headimgurl     string `json:"headimgurl,omitempty"`      //用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
-	SubscribeTime  int    `json:"subscribe_time,omitempty"`  //用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
-	Unionid        string `json:"unionid,omitempty"`         //只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
-	Remark         string `json:"remark,omitempty"`          //公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注
-	Groupid        int    `json:"groupid,omitempty"`         //用户所在的分组ID(兼容旧的用户分组接口)
-	TagidList      []int  `json:"tagid_list,omitempty"`      //用户被打上的标签ID列表
-	SubscribeScene string `json:"subscribe_scene,omitempty"` //返回用户关注的渠道来源,ADD_SCENE_SEARCH 公众号搜索,ADD_SCENE_ACCOUNT_MIGRATION 公众号迁移,ADD_SCENE_PROFILE_CARD 名片分享,ADD_SCENE_QR_CODE 扫描二维码,ADD_SCENEPROFILE LINK 图文页内名称点击,ADD_SCENE_PROFILE_ITEM 图文页右上角菜单,ADD_SCENE_PAID 支付后关注,ADD_SCENE_OTHERS 其他
-	QrScene        int    `json:"qr_scene,omitempty"`        //二维码扫码场景(开发者自定义)
-	QrSceneStr     string `json:"qr_scene_str,omitempty"`    //二维码扫码场景描述(开发者自定义)
-	Errcode        int    `json:"errcode,omitempty"`         //错误码
-	Errmsg         string `json:"errmsg,omitempty"`          //错误信息
+	Subscribe      int    `json:"subscribe,omitempty"`       // 用户是否订阅该公众号标识,值为0时,代表此用户没有关注该公众号,拉取不到其余信息。
+	Openid         string `json:"openid,omitempty"`          // 用户唯一标识
+	Nickname       string `json:"nickname,omitempty"`        // 用户的昵称
+	Sex            int    `json:"sex,omitempty"`             // 用户的性别,值为1时是男性,值为2时是女性,值为0时是未知
+	Language       string `json:"language,omitempty"`        // 用户的语言,简体中文为zh_CN
+	City           string `json:"city,omitempty"`            // 用户所在城市
+	Province       string `json:"province,omitempty"`        // 用户所在省份
+	Country        string `json:"country,omitempty"`         // 用户所在国家
+	Headimgurl     string `json:"headimgurl,omitempty"`      // 用户头像,最后一个数值代表正方形头像大小(有0、46、64、96、132数值可选,0代表640*640正方形头像),用户没有头像时该项为空。若用户更换头像,原有头像URL将失效。
+	SubscribeTime  int    `json:"subscribe_time,omitempty"`  // 用户关注时间,为时间戳。如果用户曾多次关注,则取最后关注时间
+	Unionid        string `json:"unionid,omitempty"`         // 只有在用户将公众号绑定到微信开放平台帐号后,才会出现该字段。
+	Remark         string `json:"remark,omitempty"`          // 公众号运营者对粉丝的备注,公众号运营者可在微信公众平台用户管理界面对粉丝添加备注
+	Groupid        int    `json:"groupid,omitempty"`         // 用户所在的分组ID(兼容旧的用户分组接口)
+	TagidList      []int  `json:"tagid_list,omitempty"`      // 用户被打上的标签ID列表
+	SubscribeScene string `json:"subscribe_scene,omitempty"` // 返回用户关注的渠道来源,ADD_SCENE_SEARCH 公众号搜索,ADD_SCENE_ACCOUNT_MIGRATION 公众号迁移,ADD_SCENE_PROFILE_CARD 名片分享,ADD_SCENE_QR_CODE 扫描二维码,ADD_SCENEPROFILE LINK 图文页内名称点击,ADD_SCENE_PROFILE_ITEM 图文页右上角菜单,ADD_SCENE_PAID 支付后关注,ADD_SCENE_OTHERS 其他
+	QrScene        int    `json:"qr_scene,omitempty"`        // 二维码扫码场景(开发者自定义)
+	QrSceneStr     string `json:"qr_scene_str,omitempty"`    // 二维码扫码场景描述(开发者自定义)
+	Errcode        int    `json:"errcode,omitempty"`         // 错误码
+	Errmsg         string `json:"errmsg,omitempty"`          // 错误信息
 }
 }
 
 
-//微信小程序解密后 用户手机号结构体
+// 微信小程序解密后 用户手机号结构体
 type WeChatUserPhone struct {
 type WeChatUserPhone struct {
 	PhoneNumber     string        `json:"phoneNumber,omitempty"`
 	PhoneNumber     string        `json:"phoneNumber,omitempty"`
 	PurePhoneNumber string        `json:"purePhoneNumber,omitempty"`
 	PurePhoneNumber string        `json:"purePhoneNumber,omitempty"`
@@ -303,7 +303,7 @@ type WeChatUserPhone struct {
 	Watermark       watermarkInfo `json:"watermark,omitempty"`
 	Watermark       watermarkInfo `json:"watermark,omitempty"`
 }
 }
 
 
-//微信小程序解密后 用户信息结构体
+// 微信小程序解密后 用户信息结构体
 type WeChatAppletUserInfo struct {
 type WeChatAppletUserInfo struct {
 	OpenId    string        `json:"openId,omitempty"`
 	OpenId    string        `json:"openId,omitempty"`
 	NickName  string        `json:"nickName,omitempty"`
 	NickName  string        `json:"nickName,omitempty"`
@@ -321,7 +321,7 @@ type watermarkInfo struct {
 	Timestamp int    `json:"timestamp,omitempty"`
 	Timestamp int    `json:"timestamp,omitempty"`
 }
 }
 
 
-//授权码查询openid 返回
+// 授权码查询openid 返回
 type OpenIdByAuthCodeRsp struct {
 type OpenIdByAuthCodeRsp struct {
 	ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
 	ReturnCode string `xml:"return_code,omitempty" json:"return_code,omitempty"`
 	ReturnMsg  string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
 	ReturnMsg  string `xml:"return_msg,omitempty" json:"return_msg,omitempty"`
@@ -331,10 +331,10 @@ type OpenIdByAuthCodeRsp struct {
 	Sign       string `xml:"sign,omitempty" json:"sign,omitempty"`
 	Sign       string `xml:"sign,omitempty" json:"sign,omitempty"`
 	ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"`
 	ResultCode string `xml:"result_code,omitempty" json:"result_code,omitempty"`
 	ErrCode    string `xml:"err_code,omitempty" json:"err_code,omitempty"`
 	ErrCode    string `xml:"err_code,omitempty" json:"err_code,omitempty"`
-	Openid     string `xml:"openid,omitempty" json:"openid,omitempty"` //用户唯一标识
+	Openid     string `xml:"openid,omitempty" json:"openid,omitempty"` // 用户唯一标识
 }
 }
 
 
-//App应用微信第三方登录,code换取access_token
+// App应用微信第三方登录,code换取access_token
 type AppWeChatLoginAccessToken struct {
 type AppWeChatLoginAccessToken struct {
 	AccessToken  string `json:"access_token,omitempty"`
 	AccessToken  string `json:"access_token,omitempty"`
 	ExpiresIn    int    `json:"expires_in,omitempty"`
 	ExpiresIn    int    `json:"expires_in,omitempty"`
@@ -342,17 +342,17 @@ type AppWeChatLoginAccessToken struct {
 	RefreshToken string `json:"refresh_token,omitempty"`
 	RefreshToken string `json:"refresh_token,omitempty"`
 	Scope        string `json:"scope,omitempty"`
 	Scope        string `json:"scope,omitempty"`
 	Unionid      string `json:"unionid,omitempty"`
 	Unionid      string `json:"unionid,omitempty"`
-	Errcode      int    `json:"errcode,omitempty"` //错误码
-	Errmsg       string `json:"errmsg,omitempty"`  //错误信息
+	Errcode      int    `json:"errcode,omitempty"` // 错误码
+	Errmsg       string `json:"errmsg,omitempty"`  // 错误信息
 }
 }
 
 
-//刷新App应用微信第三方登录后,获取的 access_token
+// 刷新App应用微信第三方登录后,获取的 access_token
 type RefreshAppWeChatLoginAccessTokenRsp struct {
 type RefreshAppWeChatLoginAccessTokenRsp struct {
 	AccessToken  string `json:"access_token,omitempty"`
 	AccessToken  string `json:"access_token,omitempty"`
 	ExpiresIn    int    `json:"expires_in,omitempty"`
 	ExpiresIn    int    `json:"expires_in,omitempty"`
 	Openid       string `json:"openid,omitempty"`
 	Openid       string `json:"openid,omitempty"`
 	RefreshToken string `json:"refresh_token,omitempty"`
 	RefreshToken string `json:"refresh_token,omitempty"`
 	Scope        string `json:"scope,omitempty"`
 	Scope        string `json:"scope,omitempty"`
-	Errcode      int    `json:"errcode,omitempty"` //错误码
-	Errmsg       string `json:"errmsg,omitempty"`  //错误信息
+	Errcode      int    `json:"errcode,omitempty"` // 错误码
+	Errmsg       string `json:"errmsg,omitempty"`  // 错误信息
 }
 }