param.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242
  1. package alipay
  2. import (
  3. "crypto"
  4. "crypto/rand"
  5. "crypto/rsa"
  6. "crypto/sha1"
  7. "crypto/sha256"
  8. "crypto/x509"
  9. "encoding/base64"
  10. "encoding/pem"
  11. "errors"
  12. "fmt"
  13. "hash"
  14. "log"
  15. "net/url"
  16. "time"
  17. "github.com/iGoogle-ink/gopay"
  18. )
  19. // AppId string `json:"app_id"` //支付宝分配给开发者的应用ID
  20. // Method string `json:"method"` //接口名称
  21. // Format string `json:"format"` //仅支持 JSON
  22. // ReturnUrl string `json:"return_url"` //HTTP/HTTPS开头字符串
  23. // Charset string `json:"charset"` //请求使用的编码格式,如utf-8,gbk,gb2312等,推荐使用 utf-8
  24. // SignType string `json:"sign_type"` //商户生成签名字符串所使用的签名算法类型,目前支持RSA2和RSA,推荐使用 RSA2
  25. // Sign string `json:"sign"` //商户请求参数的签名串
  26. // Timestamp string `json:"timestamp"` //发送请求的时间,格式"yyyy-MM-dd HH:mm:ss"
  27. // Version string `json:"version"` //调用的接口版本,固定为:1.0
  28. // NotifyUrl string `json:"notify_url"` //支付宝服务器主动通知商户服务器里指定的页面http/https路径。
  29. // BizContent string `json:"biz_content"` //业务请求参数的集合,最大长度不限,除公共参数外所有请求参数都必须放在这个参数中传递,具体参照各产品快速接入文档
  30. type OpenApiRoyaltyDetailInfoPojo struct {
  31. RoyaltyType string `json:"royalty_type,omitempty"`
  32. TransOut string `json:"trans_out,omitempty"`
  33. TransOutType string `json:"trans_out_type,omitempty"`
  34. TransInType string `json:"trans_in_type,omitempty"`
  35. TransIn string `json:"trans_in"`
  36. Amount string `json:"amount,omitempty"`
  37. Desc string `json:"desc,omitempty"`
  38. }
  39. // 设置 支付宝 私钥类型,alipay.PKCS1 或 alipay.PKCS8,默认 PKCS1
  40. func (a *Client) SetPrivateKeyType(t PKCSType) (client *Client) {
  41. a.mu.Lock()
  42. a.PrivateKeyType = t
  43. a.mu.Unlock()
  44. return a
  45. }
  46. // 设置 时区,不设置或出错均为默认服务器时间
  47. func (a *Client) SetLocation(name string) (client *Client) {
  48. location, err := time.LoadLocation(name)
  49. if err != nil {
  50. log.Println("set Location err, default UTC")
  51. return a
  52. }
  53. a.mu.Lock()
  54. a.LocationName = name
  55. a.location = location
  56. a.mu.Unlock()
  57. return a
  58. }
  59. // 设置 应用公钥证书SN
  60. // appCertSN:应用公钥证书SN,通过 alipay.GetCertSN() 获取
  61. func (a *Client) SetAppCertSN(appCertSN string) (client *Client) {
  62. a.mu.Lock()
  63. a.AppCertSN = appCertSN
  64. a.mu.Unlock()
  65. return a
  66. }
  67. // 设置 支付宝公钥证书SN
  68. // aliPayPublicCertSN:支付宝公钥证书SN,通过 alipay.GetCertSN() 获取
  69. func (a *Client) SetAliPayPublicCertSN(aliPayPublicCertSN string) (client *Client) {
  70. a.mu.Lock()
  71. a.AliPayPublicCertSN = aliPayPublicCertSN
  72. a.mu.Unlock()
  73. return a
  74. }
  75. // 设置 支付宝CA根证书SN
  76. // aliPayRootCertSN:支付宝CA根证书SN,通过 alipay.GetRootCertSN() 获取
  77. func (a *Client) SetAliPayRootCertSN(aliPayRootCertSN string) (client *Client) {
  78. a.mu.Lock()
  79. a.AliPayRootCertSN = aliPayRootCertSN
  80. a.mu.Unlock()
  81. return a
  82. }
  83. // 设置 app_cert_sn、alipay_root_cert_sn、alipay_cert_sn 通过应用公钥证书路径
  84. // appCertPath:应用公钥证书路径
  85. // aliPayRootCertPath:支付宝根证书文件路径
  86. // aliPayPublicCertPath:支付宝公钥证书文件路径
  87. func (a *Client) SetCertSnByPath(appCertPath, aliPayRootCertPath, aliPayPublicCertPath string) (err error) {
  88. appCertSn, err := GetCertSN(appCertPath)
  89. if err != nil {
  90. return fmt.Errorf("get app_cert_sn return err, but alse return alipay client. err: %w", err)
  91. }
  92. rootCertSn, err := GetRootCertSN(aliPayRootCertPath)
  93. if err != nil {
  94. return fmt.Errorf("get alipay_root_cert_sn return err, but alse return alipay client. err: %w", err)
  95. }
  96. publicCertSn, err := GetCertSN(aliPayPublicCertPath)
  97. if err != nil {
  98. return fmt.Errorf("get alipay_cert_sn return err, but alse return alipay client. err: %w", err)
  99. }
  100. a.mu.Lock()
  101. a.AppCertSN = appCertSn
  102. a.AliPayRootCertSN = rootCertSn
  103. a.AliPayPublicCertSN = publicCertSn
  104. a.mu.Unlock()
  105. return nil
  106. }
  107. // 设置支付后的ReturnUrl
  108. func (a *Client) SetReturnUrl(url string) (client *Client) {
  109. a.mu.Lock()
  110. a.ReturnUrl = url
  111. a.mu.Unlock()
  112. return a
  113. }
  114. // 设置支付宝服务器主动通知商户服务器里指定的页面http/https路径。
  115. func (a *Client) SetNotifyUrl(url string) (client *Client) {
  116. a.mu.Lock()
  117. a.NotifyUrl = url
  118. a.mu.Unlock()
  119. return a
  120. }
  121. // 设置编码格式,如utf-8,gbk,gb2312等,默认推荐使用 utf-8
  122. func (a *Client) SetCharset(charset string) (client *Client) {
  123. a.mu.Lock()
  124. if charset == gopay.NULL {
  125. a.Charset = "utf-8"
  126. } else {
  127. a.Charset = charset
  128. }
  129. a.mu.Unlock()
  130. return a
  131. }
  132. // 设置签名算法类型,目前支持RSA2和RSA,默认推荐使用 RSA2
  133. func (a *Client) SetSignType(signType string) (client *Client) {
  134. a.mu.Lock()
  135. if signType == gopay.NULL {
  136. a.SignType = RSA2
  137. } else {
  138. a.SignType = signType
  139. }
  140. a.mu.Unlock()
  141. return a
  142. }
  143. // 设置应用授权
  144. func (a *Client) SetAppAuthToken(appAuthToken string) (client *Client) {
  145. a.mu.Lock()
  146. a.AppAuthToken = appAuthToken
  147. a.mu.Unlock()
  148. return a
  149. }
  150. // 设置用户信息授权
  151. func (a *Client) SetAuthToken(authToken string) (client *Client) {
  152. a.mu.Lock()
  153. a.AuthToken = authToken
  154. a.mu.Unlock()
  155. return a
  156. }
  157. // 获取支付宝参数签名
  158. // bm:签名参数
  159. // signType:签名类型,alipay.RSA 或 alipay.RSA2
  160. // t:私钥类型,alipay.PKCS1 或 alipay.PKCS1,默认 PKCS1
  161. // privateKey:应用私钥,支持PKCS1和PKCS8
  162. func GetRsaSign(bm gopay.BodyMap, signType string, t PKCSType, privateKey string) (sign string, err error) {
  163. var (
  164. block *pem.Block
  165. h hash.Hash
  166. key *rsa.PrivateKey
  167. hashs crypto.Hash
  168. encryptedBytes []byte
  169. )
  170. pk := FormatPrivateKey(privateKey)
  171. if block, _ = pem.Decode([]byte(pk)); block == nil {
  172. return gopay.NULL, errors.New("pem.Decode:privateKey decode error")
  173. }
  174. switch t {
  175. case PKCS1:
  176. if key, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
  177. return gopay.NULL, err
  178. }
  179. case PKCS8:
  180. pkcs8Key, err := x509.ParsePKCS8PrivateKey(block.Bytes)
  181. if err != nil {
  182. return gopay.NULL, err
  183. }
  184. pk8, ok := pkcs8Key.(*rsa.PrivateKey)
  185. if !ok {
  186. return gopay.NULL, errors.New("parse PKCS8 key error")
  187. }
  188. key = pk8
  189. default:
  190. if key, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
  191. return gopay.NULL, err
  192. }
  193. }
  194. switch signType {
  195. case RSA:
  196. h = sha1.New()
  197. hashs = crypto.SHA1
  198. case RSA2:
  199. h = sha256.New()
  200. hashs = crypto.SHA256
  201. default:
  202. h = sha256.New()
  203. hashs = crypto.SHA256
  204. }
  205. if _, err = h.Write([]byte(bm.EncodeAliPaySignParams())); err != nil {
  206. return
  207. }
  208. if encryptedBytes, err = rsa.SignPKCS1v15(rand.Reader, key, hashs, h.Sum(nil)); err != nil {
  209. return
  210. }
  211. sign = base64.StdEncoding.EncodeToString(encryptedBytes)
  212. return
  213. }
  214. // 格式化请求URL参数
  215. func FormatURLParam(body gopay.BodyMap) (urlParam string) {
  216. v := url.Values{}
  217. for key, value := range body {
  218. v.Add(key, value.(string))
  219. }
  220. return v.Encode()
  221. }