jssdk.go 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. package wx
  2. import (
  3. "bytes"
  4. "crypto/md5"
  5. "crypto/sha1"
  6. "encoding/json"
  7. "fmt"
  8. "io/ioutil"
  9. "math/rand"
  10. "net/http"
  11. "net/url"
  12. "sort"
  13. "strings"
  14. "sync"
  15. "time"
  16. )
  17. type TicketResponse struct {
  18. ErrCode int `json:"errcode"`
  19. ErrMsg string `json:"errmsg"`
  20. Ticket string `json:"ticket"`
  21. ExpiresIn int64 `json:"expires_in"`
  22. }
  23. type SignPackage map[string]interface{}
  24. type JsSdk interface {
  25. GenerateNoncestr(length int) string
  26. GetTicket(token string) (*TicketResponse, error)
  27. ComputeSignature(token, ticket, signUrl string) (SignPackage, error)
  28. ComputePaySignature(params PkgComponents, apikey string) string
  29. }
  30. type JsSdkDefault struct {
  31. }
  32. func NewJsSdk() JsSdk {
  33. return &JsSdkDefault{}
  34. }
  35. var chars string = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
  36. var bufPool = sync.Pool{
  37. New: func() interface{} {
  38. return new(bytes.Buffer)
  39. },
  40. }
  41. func (sdk *JsSdkDefault) GenerateNoncestr(length int) string {
  42. buf := bufPool.Get().(*bytes.Buffer)
  43. defer func() {
  44. buf.Reset()
  45. bufPool.Put(buf)
  46. }()
  47. var ridx int
  48. upBound := len(chars)
  49. for i := 0; i < length; i++ {
  50. ridx = rand.Intn(upBound)
  51. buf.WriteByte(chars[ridx])
  52. }
  53. return buf.String()
  54. }
  55. func (sdk *JsSdkDefault) GetTicket(accessToken string) (*TicketResponse, error) {
  56. serviceUrl := "https://api.weixin.qq.com/cgi-bin/ticket/getticket"
  57. reqParams := url.Values{}
  58. reqParams.Add("type", "jsapi")
  59. reqParams.Add("access_token", accessToken)
  60. serviceUrl += "?" + reqParams.Encode()
  61. res, err := http.Get(serviceUrl)
  62. if err != nil {
  63. return nil, err
  64. }
  65. defer res.Body.Close()
  66. bytesBuf, err := ioutil.ReadAll(res.Body)
  67. if err != nil {
  68. return nil, err
  69. }
  70. ticketRes := &TicketResponse{}
  71. err = json.Unmarshal(bytesBuf, ticketRes)
  72. if err != nil {
  73. return nil, err
  74. }
  75. return ticketRes, nil
  76. }
  77. func (sdk *JsSdkDefault) ComputeSignature(accessToken, ticket, signUrl string) (SignPackage, error) {
  78. timestamp := time.Now().Unix()
  79. noncestr := sdk.GenerateNoncestr(16)
  80. params := PkgComponents{
  81. "jsapi_ticket": ticket,
  82. "noncestr": noncestr,
  83. "timestamp": fmt.Sprintf("%d", timestamp),
  84. "url": signUrl,
  85. }
  86. rawStr := params.buildRawQueryString()
  87. signature := sha1.Sum([]byte(rawStr))
  88. return SignPackage{
  89. "access_token": accessToken,
  90. "ticket": ticket,
  91. "noncestr": noncestr,
  92. "timestamp": timestamp,
  93. "signature": fmt.Sprintf("%x", signature),
  94. }, nil
  95. }
  96. func (sdk *JsSdkDefault) ComputePaySignature(components PkgComponents, apikey string) string {
  97. rawStr := components.buildRawQueryString() + "&key=" + apikey
  98. signature := md5.Sum([]byte(rawStr))
  99. return strings.ToUpper(fmt.Sprintf("%x", signature))
  100. }
  101. type PkgComponents map[string]string
  102. func (pc PkgComponents) buildRawQueryString() string {
  103. qstr := ""
  104. keys := []string{}
  105. for key := range pc {
  106. keys = append(keys, key)
  107. }
  108. sort.Strings(keys)
  109. for _, key := range keys {
  110. if pc[key] == "" {
  111. continue
  112. }
  113. qstr += key + "=" + pc[key] + "&"
  114. }
  115. return qstr[0 : len(qstr)-1]
  116. }